From 381a3c7ed397b9e5b19d5b1511625a173140b4de Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Fri, 18 Mar 2022 17:57:28 +0000 Subject: [PATCH 001/133] Add DelimiterSyntax.md --- Documentation/Evolution/DelimiterSyntax.md | 164 +++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 Documentation/Evolution/DelimiterSyntax.md diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md new file mode 100644 index 000000000..436c27a84 --- /dev/null +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -0,0 +1,164 @@ +# Regular Expression Literal Delimiters + +- Authors: Hamish Knight, Michael Ilseman + +## Introduction + +**TODO** + +**TODO: Motivation for regex literals in the first place? Or is that a given?** + +**TODO: Overview of regex literals in other languages?** + +## Detailed Design + +A regular expression literal will be introduced using `re'...'` delimiters, within which the compiler will parse a regular expression (the details of which are outlined in [the Regex Syntax pitch][internal-syntax]): + +``` +// Matches " = ", extracting the identifier and hex number +let regex = re'([[:alpha:]]\w*) = ([0-9A-F]+)' +``` + +The use of a two letter prefix allows for easy future extensibility of such literals, by allowing different prefixes to indicate different types of literal. **TODO: examples** + +### Parsing ambiguities + +The use of a single quote delimiter has a minor conflict with a couple of items of regex grammar, mainly around named groups. This includes `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, and `(?C'arg')`. Fortunately, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`. However we still aim to parse the single quote variants of the syntax to achieve the syntactic superset of regex grammar. + +To do this, a heuristic will be used when lexing a regex literal, and will check for the ending sequences `(?`, `(?(`, `\g`, `\k` and `(?C`. On encountering these, the lexer will attempt to scan ahead to the next `'` character, and then to the `'` that closes the literal. It should be noted that these are not valid regex endings, and as such this cannot break valid code. + +**TODO: Or do we want to insist on the user using raw `re#'...'#` syntax?** + +## Future Directions + +### Raw literals + +The `re'...'` syntax could be naturally extended to supporting "raw text" through allowing additional `#` characters to surround the quote characters e.g `re#'...'#`. Such literals would follow the same rules as the string literals introduced in [SE-0200]. + +In particular: + +- `\` and `'` characters would become literal, e.g `re#''\n''#` expresses a regular expression pattern that literally matches against the characters `'\n'` (including the quotes). +- Any number of `#` characters may surround the literal. +- Escape sequences would require the same number of `#` characters as in the delimiter to be treated specially. For example, `re##'\##n'##` would be required for a newline character sequence. + +### Multi-line literals + +A natural extension to the `re'...'` syntax to support multi-line regex literals would be to allow triple quote syntax: + +``` +re''' + abc + def + ''' +``` + +This would follow the precedent set by [SE-0168] for multi-line string literals, and obey the same rules, in particular with the stripping of any leading whitespace prior to the position of the closing delimiter. + +## Alternatives Considered + +### Double quoted `re"...."` + +We could choose to use double quotes instead of single quotes. This would be similar in appearance to string literals, however it could be argued that regex literals are distinct from string literals in that they introduce their own specific language to parse. As such, regex literals are more like "program literals" than "data literals", and the use of single quote instead of double quote could express this difference. + +### Single letter `r'...'` + +We could choose to shorten the literal prefix to just `r`. However this could potentially be confused to mean "raw", especially as Python uses this syntax for raw strings. The syntax `re'...'` could also set the precedent for a 2 letter namespace for future literals. + +### Forward slashes `/.../` + +Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternative choices). However, they would be an awkward fit in Swift's language grammar, and would not provide a path for extensibility. + +#### Parsing ambiguities + +The primary parsing ambiguity with `/.../` delimiters is with comment syntax. + +An empty regex literal would conflict with line comment syntax `//`. While this isn't a particularly useful thing to express, it may lead to an awkward user typing experience. In particular, as you begin to type a regex literal, a comment could be formed before you start typing the contents. This could however be mitigated by source tooling. + +Line comment syntax additionally means that a potential multi-line version of a regular expression literal would not be able to use `///` delimiters, in accordance with the precedent set by multi-line string literals `"""`. + +There is also a conflict with block comment syntax, when surrounding a regex literal ending with `*`, for example: + +```swift +/* +let regex = /x*/ +*/ +``` + +In this case, the block comment would prematurely end on the second line, rather than extending all the way to the third line as the user would expect. This is already an issue today with `*/` in a string literal, however it is much more likely to occur in a regular expression given the prevalence of the `*` quantifier. + +Block comment syntax also means that a regex literal would not be able to start with the `*` character, however this is less of a concern as it would not be valid regex syntax. + +Finally, there would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required `x + /y/` for regex literal interpretation. + +#### Regex limitations + +Another ambiguity with `/.../` arises when it is used to start a new line. This is particularly problematic for result builders, where we expect it to be frequently used, for example: + +```swift +Builder { + 1 + / 2 / + 3 +} +``` + +This is parsed as a single operator chain, however it is likely the user is expecting a regex literal. To resolve this ambiguity, a regex literal may not start with a space or tab character. This takes advantage of the fact that infix operators require consistent spacing. + +If a space or tab is needed as the first character, it must be escaped, e.g: + +```swift +Builder { + 1 + /\ 2 / + 3 +} +``` + +**TODO: Regex starting with `)`** + +#### Language changes required + +In addition to ambiguities listed above, there are also some parsing ambiguities that would require the following language changes: + +- Deprecation of prefix operators containing the `/` character. +- Potentially parsing `/,` as the start of a regex literal rather than an unapplied operator in an argument list e.g `fn(/, 5) + fn(/, 3)`. + +
Rationale + +##### Prefix operators starting with `/` + +We'd need to ban prefix operators starting with `/`, to avoid ambiguity with cases such as: + +```swift +let x = /0; let y = 1/ +let z = /^x^/ +``` + +Postfix `/` operators would be okay, as they'd only be treated as regex literal delimiters if we were already trying to lex as a regex literal. + +##### Prefix operators containing `/` + +Prefix operators *containing* `/` (not just at the start) would likely need banning too, in order to allow prefix operators to be used with regex literals in an unambiguous way, e.g: + +```swift +let x = !/y / .foo() +``` + +Otherwise it would be interpreted as the prefix operator `!/` by default, and require parens `!(/y /)` for regex parsing. + +##### Comma as the starting character of a regex literal + +**TODO: Or do we want to ban it as the starting character?** + +### Pound slash `#/.../#` + +This would be less syntactically ambiguous than `/.../`, while retaining some of the term-of-art familiarity. It would also provide a natural path through which to introduce `/.../` in a new language mode, as users could drop the `#` characters once they upgrade. + +However this option would also have the same block comment issue as `/.../` where e.g `#/x*/#` nested inside a block comment would prematurely end. Similarly, it's not clear how a multi-line version of the literal would be spelled. + +Additionally, introducing this syntax would introduce an inconsistency with raw string literal syntax, as `#/.../#` on its own would not treat backslashes as literal, unlike `#"..."#`. If raw regex syntax were implemented, it would start at `##/.../##`. With raw strings, escape sequences must use the same number of `#`s as the delimiter, e.g `#"\#n"#` for a newline. However for raw regex literals it would be one fewer `#` than the delimiter e.g `##/\#n/##`. + + +[SE-0168]: https://github.com/apple/swift-evolution/blob/main/proposals/0168-multi-line-string-literals.md +[SE-0200]: https://github.com/apple/swift-evolution/blob/main/proposals/0200-raw-string-escaping.md +[internal-syntax]: https://forums.swift.org/t/pitch-regex-syntax/55711 From c79f457b738c74f5a85e22f1f2ce8d38e905b360 Mon Sep 17 00:00:00 2001 From: David Ewing Date: Sat, 19 Mar 2022 23:34:06 -0600 Subject: [PATCH 002/133] Expand on parsing issues with `/` as delimited. Add a note about editor support. --- Documentation/Evolution/DelimiterSyntax.md | 38 ++++++++++++++++------ 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 436c27a84..c8ba8b0ed 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -1,6 +1,6 @@ # Regular Expression Literal Delimiters -- Authors: Hamish Knight, Michael Ilseman +- Authors: Hamish Knight, Michael Ilseman, David Ewing ## Introduction @@ -29,6 +29,7 @@ To do this, a heuristic will be used when lexing a regex literal, and will check **TODO: Or do we want to insist on the user using raw `re#'...'#` syntax?** + ## Future Directions ### Raw literals @@ -66,17 +67,17 @@ We could choose to shorten the literal prefix to just `r`. However this could po ### Forward slashes `/.../` -Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternative choices). However, they would be an awkward fit in Swift's language grammar, and would not provide a path for extensibility. +Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternative choices). However, they would be an awkward fit in Swift's language grammar, and would not provide a path for extensibility. Here we give an extensive list of drawbacks to the choice. While no individual issue is terribly bad and each could be overcome, the list of issues is quite long. #### Parsing ambiguities -The primary parsing ambiguity with `/.../` delimiters is with comment syntax. +The obvious parsing ambiguity with `/.../` delimiters is with comment syntaxes. -An empty regex literal would conflict with line comment syntax `//`. While this isn't a particularly useful thing to express, it may lead to an awkward user typing experience. In particular, as you begin to type a regex literal, a comment could be formed before you start typing the contents. This could however be mitigated by source tooling. +- An empty regex literal would conflict with line comment syntax `//`. But this isn't a particularly useful thing to express, and could be disallowed. -Line comment syntax additionally means that a potential multi-line version of a regular expression literal would not be able to use `///` delimiters, in accordance with the precedent set by multi-line string literals `"""`. +- The obvious choice for a multi-line regular expression literal would be to use `///` delimiters, in accordance with the precedent set by multi-line string literals `"""`. A different multi-line delimiter would be needed, with no obvious choice. -There is also a conflict with block comment syntax, when surrounding a regex literal ending with `*`, for example: +- There is also a conflict with block comment syntax, when surrounding a regex literal ending with `*`, for example: ```swift /* @@ -84,11 +85,11 @@ let regex = /x*/ */ ``` -In this case, the block comment would prematurely end on the second line, rather than extending all the way to the third line as the user would expect. This is already an issue today with `*/` in a string literal, however it is much more likely to occur in a regular expression given the prevalence of the `*` quantifier. + In this case, the block comment would prematurely end on the second line, rather than extending all the way to the third line as the user would expect. This is already an issue today with `*/` in a string literal, however it is much more likely to occur in a regular expression given the prevalence of the `*` quantifier. -Block comment syntax also means that a regex literal would not be able to start with the `*` character, however this is less of a concern as it would not be valid regex syntax. +- Block comment syntax also means that a regex literal would not be able to start with the `*` character, however this is less of a concern as it would not be valid regex syntax. -Finally, there would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required `x + /y/` for regex literal interpretation. +- Finally, there would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required `x + /y/` for regex literal interpretation. #### Regex limitations @@ -145,11 +146,28 @@ let x = !/y / .foo() ``` Otherwise it would be interpreted as the prefix operator `!/` by default, and require parens `!(/y /)` for regex parsing. + + + +**TODO: More cases from slack discussion ** + +```swift +func foo(_ x: (Int, Int) -> Int, _ y: (Int, Int) -> Int) {} +foo(/, /) +``` + +`foo(/, "(") / 2` !!! + + ##### Comma as the starting character of a regex literal **TODO: Or do we want to ban it as the starting character?** - + +#### Editor Considerations + +Many source editors in use today do rather simplistic syntax coloring of programming languages. And there's a long history of complaints about syntax coloring of regular expressions in Perl, JavaScript and Ruby to be found on the internet. While the most popular editors do a very good job recognizing the most common incantations of a regular expression in each language, most still don't get it 100% right. There's just a lot of work involved in doing that. If parsing Swift regular expressions is as difficult as these other languages because of the choice of delimiter, it becomes a barrier to entry for support by those editors. + ### Pound slash `#/.../#` This would be less syntactically ambiguous than `/.../`, while retaining some of the term-of-art familiarity. It would also provide a natural path through which to introduce `/.../` in a new language mode, as users could drop the `#` characters once they upgrade. From 731292e2ad3bffbc261edc9abe90ffc875c3c89e Mon Sep 17 00:00:00 2001 From: David Ewing Date: Sun, 20 Mar 2022 21:54:34 -0600 Subject: [PATCH 003/133] Rewrite that Editor Considerations paragraph. --- Documentation/Evolution/DelimiterSyntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index c8ba8b0ed..b870f521e 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -166,7 +166,7 @@ foo(/, /) #### Editor Considerations -Many source editors in use today do rather simplistic syntax coloring of programming languages. And there's a long history of complaints about syntax coloring of regular expressions in Perl, JavaScript and Ruby to be found on the internet. While the most popular editors do a very good job recognizing the most common incantations of a regular expression in each language, most still don't get it 100% right. There's just a lot of work involved in doing that. If parsing Swift regular expressions is as difficult as these other languages because of the choice of delimiter, it becomes a barrier to entry for support by those editors. +As described above, there would be a lot involved in handling the parsing ambiguities with `/.../` delimiters. It's one thing to do this in the compiler. But the language also has to be understood by a plethora of source code editors. Those editors either need encode all those ambiguities, or they need to provide a "best effort" at handling the most common cases. It's all too common for editors to take the "best effort" route. There's a long history of complaints with editors that don't completely support a language's features. And indeed, there's plenty of history of editors that don't correctly support regular expression literals in other languages. By choosing a literal that is easily parsed, we should avoid seeing those complaints regarding Swift. ### Pound slash `#/.../#` From 104927631a479c573a384bc55edbb474fa5d169c Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 21 Mar 2022 14:03:36 +0000 Subject: [PATCH 004/133] Change single quote constructs to be invalid --- Documentation/Evolution/DelimiterSyntax.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index b870f521e..45af08118 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -21,14 +21,11 @@ let regex = re'([[:alpha:]]\w*) = ([0-9A-F]+)' The use of a two letter prefix allows for easy future extensibility of such literals, by allowing different prefixes to indicate different types of literal. **TODO: examples** -### Parsing ambiguities +### Regex limitations -The use of a single quote delimiter has a minor conflict with a couple of items of regex grammar, mainly around named groups. This includes `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, and `(?C'arg')`. Fortunately, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`. However we still aim to parse the single quote variants of the syntax to achieve the syntactic superset of regex grammar. - -To do this, a heuristic will be used when lexing a regex literal, and will check for the ending sequences `(?`, `(?(`, `\g`, `\k` and `(?C`. On encountering these, the lexer will attempt to scan ahead to the next `'` character, and then to the `'` that closes the literal. It should be noted that these are not valid regex endings, and as such this cannot break valid code. - -**TODO: Or do we want to insist on the user using raw `re#'...'#` syntax?** +There are a few items of regex grammar that use the single quote character as a metacharacter. These include named group definitions and references such as `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, as well as callout syntax `(?C'arg')`. The use of a single quote conflicts with the `re'...'` delimiter as it will be considered the end of the literal. Fortunately, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`, and `(?C"arg")`. +As such, the single quote variants of the syntax will be considered invalid in a `re'...'` literal, and users must use the alternative syntax. If a raw variant of the syntax `re#'...'#` of the syntax is later added, that may also be used. In order to improve diagnostic behavior, the compiler will attempt to scan ahead when encountering the ending sequences `(?`, `(?(`, `\g`, `\k` and `(?C`. This will enable a more accurate error to be emitted that suggests the alternative syntax. ## Future Directions From c7d556cb6b25531b7f455b23127b641f5cf11c14 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 21 Mar 2022 14:40:25 +0000 Subject: [PATCH 005/133] Elaborate on starting character limitations --- Documentation/Evolution/DelimiterSyntax.md | 50 ++++++++++++++++------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 45af08118..8beb0b113 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -25,7 +25,7 @@ The use of a two letter prefix allows for easy future extensibility of such lite There are a few items of regex grammar that use the single quote character as a metacharacter. These include named group definitions and references such as `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, as well as callout syntax `(?C'arg')`. The use of a single quote conflicts with the `re'...'` delimiter as it will be considered the end of the literal. Fortunately, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`, and `(?C"arg")`. -As such, the single quote variants of the syntax will be considered invalid in a `re'...'` literal, and users must use the alternative syntax. If a raw variant of the syntax `re#'...'#` of the syntax is later added, that may also be used. In order to improve diagnostic behavior, the compiler will attempt to scan ahead when encountering the ending sequences `(?`, `(?(`, `\g`, `\k` and `(?C`. This will enable a more accurate error to be emitted that suggests the alternative syntax. +As such, the single quote variants of the syntax will be considered invalid in a `re'...'` literal, and users must use the alternative syntax instead. If a raw variant of the syntax `re#'...'#` of the syntax is later added, that may also be used. In order to improve diagnostic behavior, the compiler will attempt to scan ahead when encountering the ending sequences `(?`, `(?(`, `\g`, `\k` and `(?C`. This will enable a more accurate error to be emitted that suggests the alternative syntax. ## Future Directions @@ -35,7 +35,7 @@ The `re'...'` syntax could be naturally extended to supporting "raw text" throug In particular: -- `\` and `'` characters would become literal, e.g `re#''\n''#` expresses a regular expression pattern that literally matches against the characters `'\n'` (including the quotes). +- `\` and `'` characters would become literal, e.g `re#''\n''#` expresses a regular expression pattern that literally matches against the characters `'\n'` (including the quotes). **TODO: Do we really want to treat backslash as literal? Seems consistent, but escape sequences are frequently used in regex.** - Any number of `#` characters may surround the literal. - Escape sequences would require the same number of `#` characters as in the delimiter to be treated specially. For example, `re##'\##n'##` would be required for a newline character sequence. @@ -70,17 +70,17 @@ Forward slashes are a regex term of art, and are used as the delimiters for rege The obvious parsing ambiguity with `/.../` delimiters is with comment syntaxes. -- An empty regex literal would conflict with line comment syntax `//`. But this isn't a particularly useful thing to express, and could be disallowed. +- An empty regex literal would conflict with line comment syntax `//`. But this isn't a particularly useful thing to express, and can therefore be disallowed without significant impact. - The obvious choice for a multi-line regular expression literal would be to use `///` delimiters, in accordance with the precedent set by multi-line string literals `"""`. A different multi-line delimiter would be needed, with no obvious choice. -- There is also a conflict with block comment syntax, when surrounding a regex literal ending with `*`, for example: +- There is a conflict with block comment syntax, when surrounding a regex literal ending with `*`, for example: -```swift -/* -let regex = /x*/ -*/ -``` + ```swift + /* + let regex = /x*/ + */ + ``` In this case, the block comment would prematurely end on the second line, rather than extending all the way to the third line as the user would expect. This is already an issue today with `*/` in a string literal, however it is much more likely to occur in a regular expression given the prevalence of the `*` quantifier. @@ -90,7 +90,11 @@ let regex = /x*/ #### Regex limitations -Another ambiguity with `/.../` arises when it is used to start a new line. This is particularly problematic for result builders, where we expect it to be frequently used, for example: +In order to help avoid parsing ambiguities, a regex literal will not be parsed if it starts with a space, tab, or `)` character. Though the latter is already invalid regex syntax. + +
Rationale + +This is due to 2 main ambiguities. The first of which arises when a `/.../` regex literal is used to start a new line. This is particularly problematic for result builders, where we expect it to be frequently used, for example: ```swift Builder { @@ -100,7 +104,7 @@ Builder { } ``` -This is parsed as a single operator chain, however it is likely the user is expecting a regex literal. To resolve this ambiguity, a regex literal may not start with a space or tab character. This takes advantage of the fact that infix operators require consistent spacing. +This is parsed as a single operator chain, however it is likely the user is expecting a regex literal. To resolve this ambiguity, a regex literal may not start with a space or tab character. This takes advantage of the fact that infix operators require consistent spacing on either side. If a space or tab is needed as the first character, it must be escaped, e.g: @@ -112,7 +116,27 @@ Builder { } ``` -**TODO: Regex starting with `)`** +The second ambiguity arises with Swift's ability to pass an unapplied operator reference as an argument to a function, for example: + +```swift +let arr: [Double] = [2, 3, 4] +let x = arr.reduce(1, /) / 5 +``` + +The `/` in the call to `reduce` is in a valid expression context, and as such could be passed as a regular expression literal. To help mitigate this ambiguity, a regex literal will not be parsed if the first character is `)`. Note this would not be valid regex syntax anyway. + +This is also applicable to unapplied operator references in parentheses and tuples. + +It should be noted that this only mitigates the issue, as another ambiguity arises if the next character is a comma: + +```swift +func foo(_ x: (Int, Int) -> Int, _ y: (Int, Int) -> Int) {} +foo(/, /) +``` + +However we feel that starting a regex with a comma is likely to be a common case, and as such we intend to change the parser such that the above becomes a regex literal. + +
#### Language changes required @@ -161,6 +185,8 @@ foo(/, /) **TODO: Or do we want to ban it as the starting character?** +
+ #### Editor Considerations As described above, there would be a lot involved in handling the parsing ambiguities with `/.../` delimiters. It's one thing to do this in the compiler. But the language also has to be understood by a plethora of source code editors. Those editors either need encode all those ambiguities, or they need to provide a "best effort" at handling the most common cases. It's all too common for editors to take the "best effort" route. There's a long history of complaints with editors that don't completely support a language's features. And indeed, there's plenty of history of editors that don't correctly support regular expression literals in other languages. By choosing a literal that is easily parsed, we should avoid seeing those complaints regarding Swift. From 7074cfb08cd0ec58eeb106274fcfd0d520254119 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 21 Mar 2022 15:10:21 +0000 Subject: [PATCH 006/133] Elaborate on comma case --- Documentation/Evolution/DelimiterSyntax.md | 33 +++++++++++++--------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 8beb0b113..6c0eb28ab 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -90,11 +90,11 @@ The obvious parsing ambiguity with `/.../` delimiters is with comment syntaxes. #### Regex limitations -In order to help avoid parsing ambiguities, a regex literal will not be parsed if it starts with a space, tab, or `)` character. Though the latter is already invalid regex syntax. +In order to help avoid further parsing ambiguities, a regex literal will not be parsed if it starts with a space, tab, or `)` character. Though the latter is already invalid regex syntax.
Rationale -This is due to 2 main ambiguities. The first of which arises when a `/.../` regex literal is used to start a new line. This is particularly problematic for result builders, where we expect it to be frequently used, for example: +This is due to 2 main ambiguities. The first of which arises when a `/.../` regex literal starts a new line. This is particularly problematic for result builders, where we expect it to be frequently used, for example: ```swift Builder { @@ -116,16 +116,14 @@ Builder { } ``` -The second ambiguity arises with Swift's ability to pass an unapplied operator reference as an argument to a function, for example: +The second ambiguity arises with Swift's ability to pass an unapplied operator reference as an argument to a function for example: ```swift let arr: [Double] = [2, 3, 4] let x = arr.reduce(1, /) / 5 ``` -The `/` in the call to `reduce` is in a valid expression context, and as such could be passed as a regular expression literal. To help mitigate this ambiguity, a regex literal will not be parsed if the first character is `)`. Note this would not be valid regex syntax anyway. - -This is also applicable to unapplied operator references in parentheses and tuples. +The `/` in the call to `reduce` is in a valid expression context, and as such could be parsed as a regex literal. This is also applicable to operators in tuples and parentheses. To help mitigate this ambiguity, a regex literal will not be parsed if the first character is `)`. This should have minimal impact, as this would not be valid regex syntax anyway. It should be noted that this only mitigates the issue, as another ambiguity arises if the next character is a comma: @@ -143,7 +141,7 @@ However we feel that starting a regex with a comma is likely to be a common case In addition to ambiguities listed above, there are also some parsing ambiguities that would require the following language changes: - Deprecation of prefix operators containing the `/` character. -- Potentially parsing `/,` as the start of a regex literal rather than an unapplied operator in an argument list e.g `fn(/, 5) + fn(/, 3)`. +- Potentially parsing `/,` as the start of a regex literal rather than an unapplied operator in an argument list. For example, `fn(/, /)` becomes a regex literal rather than 2 unapplied operator arguments. **TODO: Or do we want to ban it as the starting character? Seems like a common regex case**
Rationale @@ -167,23 +165,32 @@ let x = !/y / .foo() ``` Otherwise it would be interpreted as the prefix operator `!/` by default, and require parens `!(/y /)` for regex parsing. + +##### Comma as the starting character of a regex literal +As stated previously, there is a parsing ambiguity with unapplied operators in argument lists, tuples, and parentheses. Some of these cases can be mitigated by not parsing a regex literal if the starting character is `)`. However it does not solve the issue when the next character is `,`, i.e `/` is used in an argument list before another argument. - -**TODO: More cases from slack discussion ** +For example: ```swift func foo(_ x: (Int, Int) -> Int, _ y: (Int, Int) -> Int) {} foo(/, /) ``` -`foo(/, "(") / 2` !!! +This is currently parsed as 2 unapplied operator arguments. However, given the fact that a regex starting with a comma is not an uncommon case, this will become a regex literal. +The above case seems uncommon, however note this may also occur when the closing `/` appears outside of the argument list, e.g: - -##### Comma as the starting character of a regex literal +```swift +foo(/, 2) + foo(/, 3) +``` + +This would also become a regex literal, i.e it would be parsed as the argument `/, 2) + foo(/`. + +**TODO: More cases from slack discussion ** + +`foo(/, "(") / 2` !!! -**TODO: Or do we want to ban it as the starting character?**
From 945219eec7b8b27ee5c6709d73ce473e4e0fb8f9 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 21 Mar 2022 15:11:26 +0000 Subject: [PATCH 007/133] grammar --- Documentation/Evolution/DelimiterSyntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 6c0eb28ab..c866619c2 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -116,7 +116,7 @@ Builder { } ``` -The second ambiguity arises with Swift's ability to pass an unapplied operator reference as an argument to a function for example: +The second ambiguity arises with Swift's ability to pass an unapplied operator reference as an argument to a function, for example: ```swift let arr: [Double] = [2, 3, 4] From d1d0d5710fc5720319f15140a5256cb7fa1c2429 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 21 Mar 2022 15:24:57 +0000 Subject: [PATCH 008/133] Add comma disambiguation --- Documentation/Evolution/DelimiterSyntax.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index c866619c2..ed8b06756 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -21,7 +21,7 @@ let regex = re'([[:alpha:]]\w*) = ([0-9A-F]+)' The use of a two letter prefix allows for easy future extensibility of such literals, by allowing different prefixes to indicate different types of literal. **TODO: examples** -### Regex limitations +### Regex syntax limitations There are a few items of regex grammar that use the single quote character as a metacharacter. These include named group definitions and references such as `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, as well as callout syntax `(?C'arg')`. The use of a single quote conflicts with the `re'...'` delimiter as it will be considered the end of the literal. Fortunately, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`, and `(?C"arg")`. @@ -88,7 +88,7 @@ The obvious parsing ambiguity with `/.../` delimiters is with comment syntaxes. - Finally, there would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required `x + /y/` for regex literal interpretation. -#### Regex limitations +#### Regex syntax limitations In order to help avoid further parsing ambiguities, a regex literal will not be parsed if it starts with a space, tab, or `)` character. Though the latter is already invalid regex syntax. @@ -141,7 +141,7 @@ However we feel that starting a regex with a comma is likely to be a common case In addition to ambiguities listed above, there are also some parsing ambiguities that would require the following language changes: - Deprecation of prefix operators containing the `/` character. -- Potentially parsing `/,` as the start of a regex literal rather than an unapplied operator in an argument list. For example, `fn(/, /)` becomes a regex literal rather than 2 unapplied operator arguments. **TODO: Or do we want to ban it as the starting character? Seems like a common regex case** +- Parsing `/,` as the start of a regex literal if a closing `/` is found, rather than an unapplied operator in an argument list. For example, `fn(/, /)` becomes a regex literal rather than 2 unapplied operator arguments. **TODO: Or do we want to ban it as the starting character? Seems like a common regex case**
Rationale @@ -185,13 +185,18 @@ The above case seems uncommon, however note this may also occur when the closing foo(/, 2) + foo(/, 3) ``` -This would also become a regex literal, i.e it would be parsed as the argument `/, 2) + foo(/`. +This would also become a regex literal, i.e it would be parsed as the argument `/, 2) + foo(/`. If users wish to disambiguate, they will need to surround at least the opening `/` with parentheses, e.g: + +```swift +foo((/), 2) + foo(/, 3) +``` + +This takes advantage of the fact that a regex literal will not be parsed if the first character is `)`. **TODO: More cases from slack discussion ** `foo(/, "(") / 2` !!! -
#### Editor Considerations From bcebfc63f7f3a77a05eb6b137b0b611e832c3044 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 21 Mar 2022 16:37:15 +0000 Subject: [PATCH 009/133] Update comma disambiguation --- Documentation/Evolution/DelimiterSyntax.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index ed8b06756..e267d2274 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -185,6 +185,8 @@ The above case seems uncommon, however note this may also occur when the closing foo(/, 2) + foo(/, 3) ``` +**TODO: Do we want to talk about a heuristic that looks for unbalanced parens? I'm kind of hesitant to implement that, as it would have edge cases and might screw with regex errors that should be diagnosed as invalid regex, rather than some cryptic Swift syntactic error. Which would also make it harder to explain to users.** + This would also become a regex literal, i.e it would be parsed as the argument `/, 2) + foo(/`. If users wish to disambiguate, they will need to surround at least the opening `/` with parentheses, e.g: ```swift @@ -193,10 +195,6 @@ foo((/), 2) + foo(/, 3) This takes advantage of the fact that a regex literal will not be parsed if the first character is `)`. -**TODO: More cases from slack discussion ** - -`foo(/, "(") / 2` !!! -
#### Editor Considerations From 1c2b7ad00d2d99fd67f764b3f53b52069e347929 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 22 Mar 2022 19:20:36 +0000 Subject: [PATCH 010/133] Flip pitch to `/.../` as the main syntax A quick pass to flip `/.../` out of the alternatives and into the main syntax. Still needs a bunch of work. Also add some commentary on a regex with `]` as the starting character. --- Documentation/Evolution/DelimiterSyntax.md | 153 +++++++++++---------- 1 file changed, 81 insertions(+), 72 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index e267d2274..c2c6287b8 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -12,61 +12,22 @@ ## Detailed Design -A regular expression literal will be introduced using `re'...'` delimiters, within which the compiler will parse a regular expression (the details of which are outlined in [the Regex Syntax pitch][internal-syntax]): +**TODO: Say that this is Swift 6 syntax only, `#/.../#` would be 5.7 syntax** + +A regular expression literal will be introduced using `/.../` delimiters, within which the compiler will parse a regular expression (the details of which are outlined in [the Regex Syntax pitch][internal-syntax]): ``` // Matches " = ", extracting the identifier and hex number -let regex = re'([[:alpha:]]\w*) = ([0-9A-F]+)' +let regex = /([[:alpha:]]\w*) = ([0-9A-F]+)/ ``` -The use of a two letter prefix allows for easy future extensibility of such literals, by allowing different prefixes to indicate different types of literal. **TODO: examples** - -### Regex syntax limitations - -There are a few items of regex grammar that use the single quote character as a metacharacter. These include named group definitions and references such as `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, as well as callout syntax `(?C'arg')`. The use of a single quote conflicts with the `re'...'` delimiter as it will be considered the end of the literal. Fortunately, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`, and `(?C"arg")`. - -As such, the single quote variants of the syntax will be considered invalid in a `re'...'` literal, and users must use the alternative syntax instead. If a raw variant of the syntax `re#'...'#` of the syntax is later added, that may also be used. In order to improve diagnostic behavior, the compiler will attempt to scan ahead when encountering the ending sequences `(?`, `(?(`, `\g`, `\k` and `(?C`. This will enable a more accurate error to be emitted that suggests the alternative syntax. - -## Future Directions - -### Raw literals +Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternative choices). Due to its existing use in comment syntax and operators, there are some syntactic ambiguities to consider. While there are quite a few cases to consider, we do not feel that the impact of any individual case is particularly high. -The `re'...'` syntax could be naturally extended to supporting "raw text" through allowing additional `#` characters to surround the quote characters e.g `re#'...'#`. Such literals would follow the same rules as the string literals introduced in [SE-0200]. +**TODO: Do we want to present a stronger argument for `/.../`?** -In particular: +**TODO: Anything else we want to say here before segueing into the massive list?** -- `\` and `'` characters would become literal, e.g `re#''\n''#` expresses a regular expression pattern that literally matches against the characters `'\n'` (including the quotes). **TODO: Do we really want to treat backslash as literal? Seems consistent, but escape sequences are frequently used in regex.** -- Any number of `#` characters may surround the literal. -- Escape sequences would require the same number of `#` characters as in the delimiter to be treated specially. For example, `re##'\##n'##` would be required for a newline character sequence. - -### Multi-line literals - -A natural extension to the `re'...'` syntax to support multi-line regex literals would be to allow triple quote syntax: - -``` -re''' - abc - def - ''' -``` - -This would follow the precedent set by [SE-0168] for multi-line string literals, and obey the same rules, in particular with the stripping of any leading whitespace prior to the position of the closing delimiter. - -## Alternatives Considered - -### Double quoted `re"...."` - -We could choose to use double quotes instead of single quotes. This would be similar in appearance to string literals, however it could be argued that regex literals are distinct from string literals in that they introduce their own specific language to parse. As such, regex literals are more like "program literals" than "data literals", and the use of single quote instead of double quote could express this difference. - -### Single letter `r'...'` - -We could choose to shorten the literal prefix to just `r`. However this could potentially be confused to mean "raw", especially as Python uses this syntax for raw strings. The syntax `re'...'` could also set the precedent for a 2 letter namespace for future literals. - -### Forward slashes `/.../` - -Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternative choices). However, they would be an awkward fit in Swift's language grammar, and would not provide a path for extensibility. Here we give an extensive list of drawbacks to the choice. While no individual issue is terribly bad and each could be overcome, the list of issues is quite long. - -#### Parsing ambiguities +### Parsing ambiguities The obvious parsing ambiguity with `/.../` delimiters is with comment syntaxes. @@ -88,7 +49,7 @@ The obvious parsing ambiguity with `/.../` delimiters is with comment syntaxes. - Finally, there would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required `x + /y/` for regex literal interpretation. -#### Regex syntax limitations +### Regex syntax limitations In order to help avoid further parsing ambiguities, a regex literal will not be parsed if it starts with a space, tab, or `)` character. Though the latter is already invalid regex syntax. @@ -125,27 +86,20 @@ let x = arr.reduce(1, /) / 5 The `/` in the call to `reduce` is in a valid expression context, and as such could be parsed as a regex literal. This is also applicable to operators in tuples and parentheses. To help mitigate this ambiguity, a regex literal will not be parsed if the first character is `)`. This should have minimal impact, as this would not be valid regex syntax anyway. -It should be noted that this only mitigates the issue, as another ambiguity arises if the next character is a comma: - -```swift -func foo(_ x: (Int, Int) -> Int, _ y: (Int, Int) -> Int) {} -foo(/, /) -``` - -However we feel that starting a regex with a comma is likely to be a common case, and as such we intend to change the parser such that the above becomes a regex literal. +It should be noted that this only mitigates the issue, as it does not handle the case where the next character is a comma or right square bracket. These cases are explored further in the following section. -#### Language changes required +### Language changes required -In addition to ambiguities listed above, there are also some parsing ambiguities that would require the following language changes: +In addition to ambiguities listed above, there are also some parsing ambiguities that would require the following language changes in Swift 6 mode: - Deprecation of prefix operators containing the `/` character. -- Parsing `/,` as the start of a regex literal if a closing `/` is found, rather than an unapplied operator in an argument list. For example, `fn(/, /)` becomes a regex literal rather than 2 unapplied operator arguments. **TODO: Or do we want to ban it as the starting character? Seems like a common regex case** +- Parsing `/,` and `/]` as the start of a regex literal if a closing `/` is found, rather than an unapplied operator in an argument list. For example, `fn(/, /)` becomes a regex literal rather than 2 unapplied operator arguments.
Rationale -##### Prefix operators starting with `/` +#### Prefix operators starting with `/` We'd need to ban prefix operators starting with `/`, to avoid ambiguity with cases such as: @@ -156,7 +110,7 @@ let z = /^x^/ Postfix `/` operators would be okay, as they'd only be treated as regex literal delimiters if we were already trying to lex as a regex literal. -##### Prefix operators containing `/` +#### Prefix operators containing `/` Prefix operators *containing* `/` (not just at the start) would likely need banning too, in order to allow prefix operators to be used with regex literals in an unambiguous way, e.g: @@ -166,49 +120,104 @@ let x = !/y / .foo() Otherwise it would be interpreted as the prefix operator `!/` by default, and require parens `!(/y /)` for regex parsing. -##### Comma as the starting character of a regex literal +#### `/,` and `/]` as regex literal openings -As stated previously, there is a parsing ambiguity with unapplied operators in argument lists, tuples, and parentheses. Some of these cases can be mitigated by not parsing a regex literal if the starting character is `)`. However it does not solve the issue when the next character is `,`, i.e `/` is used in an argument list before another argument. +As stated previously, there is a parsing ambiguity with unapplied operators in argument lists, tuples, and parentheses. Some of these cases can be mitigated by not parsing a regex literal if the starting character is `)`. However it does not solve the issue when the next character is `,` or `]`. Both of these are valid regex starting characters, and comma in particular may be a fairly common case for a regex. For example: ```swift +// Ambiguity with comma: func foo(_ x: (Int, Int) -> Int, _ y: (Int, Int) -> Int) {} foo(/, /) -``` - -This is currently parsed as 2 unapplied operator arguments. However, given the fact that a regex starting with a comma is not an uncommon case, this will become a regex literal. -The above case seems uncommon, however note this may also occur when the closing `/` appears outside of the argument list, e.g: +// Also affects cases where the closing '/' is outside the argument list. +func bar(_ fn: (Int, Int) -> Int, _ x: Int) -> Int { 0 } +bar(/, 2) + bar(/, 3) -```swift -foo(/, 2) + foo(/, 3) +// Ambiguity with right square bracket: +struct S { + subscript(_ fn: (Int, Int) -> Int) -> Int { 0 } +} +func baz(_ x: S) -> Int { + x[/] + x[/] +} ``` +`foo(/, /)` is currently parsed as 2 unapplied operator arguments. `bar(/, 2) + bar(/, 3)` is currently parsed as two independent calls that each take an unapplied `/` operator reference. Both of these would become regex literals arguments, `/, /` and `/, 2) + bar(/` respectively (though the latter would produce a regex error). + **TODO: Do we want to talk about a heuristic that looks for unbalanced parens? I'm kind of hesitant to implement that, as it would have edge cases and might screw with regex errors that should be diagnosed as invalid regex, rather than some cryptic Swift syntactic error. Which would also make it harder to explain to users.** -This would also become a regex literal, i.e it would be parsed as the argument `/, 2) + foo(/`. If users wish to disambiguate, they will need to surround at least the opening `/` with parentheses, e.g: +To disambiguate these cases, users will need to surround at least the opening `/` with parentheses, e.g: ```swift -foo((/), 2) + foo(/, 3) +foo((/), /) +bar((/), 2) + bar(/, 3) + +func baz(_ x: S) -> Int { + x[(/)] + x[/] +} ``` This takes advantage of the fact that a regex literal will not be parsed if the first character is `)`.
-#### Editor Considerations +### Editor Considerations + +**TODO: Rewrite now that `/.../` is the syntax being pitched?** As described above, there would be a lot involved in handling the parsing ambiguities with `/.../` delimiters. It's one thing to do this in the compiler. But the language also has to be understood by a plethora of source code editors. Those editors either need encode all those ambiguities, or they need to provide a "best effort" at handling the most common cases. It's all too common for editors to take the "best effort" route. There's a long history of complaints with editors that don't completely support a language's features. And indeed, there's plenty of history of editors that don't correctly support regular expression literals in other languages. By choosing a literal that is easily parsed, we should avoid seeing those complaints regarding Swift. + ### Pound slash `#/.../#` +**TODO: This needs to be rewritten to say that it's a transition syntax** + This would be less syntactically ambiguous than `/.../`, while retaining some of the term-of-art familiarity. It would also provide a natural path through which to introduce `/.../` in a new language mode, as users could drop the `#` characters once they upgrade. However this option would also have the same block comment issue as `/.../` where e.g `#/x*/#` nested inside a block comment would prematurely end. Similarly, it's not clear how a multi-line version of the literal would be spelled. Additionally, introducing this syntax would introduce an inconsistency with raw string literal syntax, as `#/.../#` on its own would not treat backslashes as literal, unlike `#"..."#`. If raw regex syntax were implemented, it would start at `##/.../##`. With raw strings, escape sequences must use the same number of `#`s as the delimiter, e.g `#"\#n"#` for a newline. However for raw regex literals it would be one fewer `#` than the delimiter e.g `##/\#n/##`. +## Future Directions + +**TODO: What do we want to say here?** + +## Alternatives Considered + +### Prefixed quote `re'...'` + +**TODO: Do a pass over this to make sure it sounds correct now that it's an alternative** + +We could choose to use `re'...'` delimiters, for example: + +``` +// Matches " = ", extracting the identifier and hex number +let regex = re'([[:alpha:]]\w*) = ([0-9A-F]+)' +``` + +**TODO: Fill in reasons why not to pick this** + +**TODO: Mention that it nicely extends to raw and multiline?** + +#### Regex syntax limitations + +There are a few items of regex grammar that use the single quote character as a metacharacter. These include named group definitions and references such as `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, as well as callout syntax `(?C'arg')`. The use of a single quote conflicts with the `re'...'` delimiter as it will be considered the end of the literal. Fortunately, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`, and `(?C"arg")`. + +As such, the single quote variants of the syntax would be considered invalid in a `re'...'` literal, and users must use the alternative syntax instead. If a raw variant of the syntax `re#'...'#` of the syntax is later added, that may also be used. In order to improve diagnostic behavior, the compiler would attempt to scan ahead when encountering the ending sequences `(?`, `(?(`, `\g`, `\k` and `(?C`. This would enable a more accurate error to be emitted that suggests the alternative syntax. + +**TODO: Do we actually want to include the below? They're less relevant if `re'...'` is itself the alternative** + +### Double quoted `re"...."` + +We could choose to use double quotes instead of single quotes. This would be similar in appearance to string literals, however it could be argued that regex literals are distinct from string literals in that they introduce their own specific language to parse. As such, regex literals are more like "program literals" than "data literals", and the use of single quote instead of double quote could express this difference. + +### Single letter `r'...'` + +We could choose to shorten the literal prefix to just `r`. However this could potentially be confused to mean "raw", especially as Python uses this syntax for raw strings. The syntax `re'...'` could also set the precedent for a 2 letter namespace for future literals. + +**TODO: Add the other alternatives e.g `#regex(...)`** [SE-0168]: https://github.com/apple/swift-evolution/blob/main/proposals/0168-multi-line-string-literals.md [SE-0200]: https://github.com/apple/swift-evolution/blob/main/proposals/0200-raw-string-escaping.md From e8411847c80233a4745e38cd7fd35fccc7fed462 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 23 Mar 2022 17:30:11 +0000 Subject: [PATCH 011/133] Update alternatives considered --- Documentation/Evolution/DelimiterSyntax.md | 52 ++++++++++++++++++---- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index c2c6287b8..b45872337 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -188,8 +188,6 @@ Additionally, introducing this syntax would introduce an inconsistency with raw ### Prefixed quote `re'...'` -**TODO: Do a pass over this to make sure it sounds correct now that it's an alternative** - We could choose to use `re'...'` delimiters, for example: ``` @@ -197,6 +195,8 @@ We could choose to use `re'...'` delimiters, for example: let regex = re'([[:alpha:]]\w*) = ([0-9A-F]+)' ``` +The use of two letter prefix could potentially be used as a namespace for future literal types. However, it is unusual for a Swift literal to be prefixed in this way. + **TODO: Fill in reasons why not to pick this** **TODO: Mention that it nicely extends to raw and multiline?** @@ -207,17 +207,53 @@ There are a few items of regex grammar that use the single quote character as a As such, the single quote variants of the syntax would be considered invalid in a `re'...'` literal, and users must use the alternative syntax instead. If a raw variant of the syntax `re#'...'#` of the syntax is later added, that may also be used. In order to improve diagnostic behavior, the compiler would attempt to scan ahead when encountering the ending sequences `(?`, `(?(`, `\g`, `\k` and `(?C`. This would enable a more accurate error to be emitted that suggests the alternative syntax. -**TODO: Do we actually want to include the below? They're less relevant if `re'...'` is itself the alternative** +### Prefixed double quote `re"...."` + +This would be a double quoted version of `re'...'`, more similar to string literal syntax. This has the advantage that single quote regex syntax e.g `(?'name')` would continue to work without requiring the use of the alternative syntax or "raw syntax" delimiters. However it could be argued that regex literals are distinct from string literals in that they introduce their own specific language to parse. As such, regex literals are more like "program literals" than "data literals", and the use of single quote instead of double quote may be useful in expressing this difference. + +### Single letter prefixed quote `r'...'` + +This would be a slightly shorter version of `re'...'`. While it's more concise, it could potentially be confused to mean "raw", especially as Python uses this syntax for raw strings. + +#### Single quotes `'...'` + +This would be an even more concise version of `re'...'` that drops the prefix entirely. However, given how close it is to string literal syntax, it may not be entirely clear to users that `'...'` denotes a regular expression as opposed to some different form of string literal (e.g some form of character literal, or a string literal with different escaping rules). + +We could help distinguish it from a string literal by requiring e.g `'/.../'`, though it may not be clear that the `/` characters are part of the delimiters rather than part of the literal. Additionally, this would potentially rule out the use of `'...'` as a future literal kind. + +#### Magic literal `#regex(...)` + +We could opt for for a more explicitly spelled out literal syntax such as `#regex(...)`. This is an even more heavyweight option, similar to `#selector(...)`. As such, it may be considered syntactically noisy as e.g a function argument `str.match(#regex([abc]+))` vs `str.match(/[abc]+/)`. -### Double quoted `re"...."` +Such a syntax would require the containing regex to correctly balance capture group parentheses, otherwise the rest of the line might be incorrectly considered a regex. This could place additional cognitive burden on the user, and may lead to an awkward typing experience. For example, if the user is editing a previously written regex, the syntax highlighting for the rest of the line may change, and unhelpful spurious errors may be reported. With a different delimiter, the compiler would be able to detect and better diagnose unbalanced parentheses in the regex. + +We could avoid the parenthesis balancing issue by requiring an additional internal delimiter such as `#regex(/.../)`. However it is even more heavyweight, and it may be unclear that `/` is part of the delimiter rather than part of the literal. Alternatively, we could replace the internal delimiter with another character such as ```#regex`...` ```, `#regex{...}`, or `#regex/.../`. However those would be inconsistent with the existing `#literal(...)` syntax and the first two would overload the existing meanings for the ``` `` ``` and `{}` delimiters. + +It should also be noted that `#regex(...)` would introduce a syntactic inconsistency where the argument of a `#literal(...)` is no longer necessarily valid Swift syntax, despite being written in the form of an argument. + +#### Shortened magic literal `#(...)` + +We could reduce the visual weight of `#regex(...)` by only requiring `#(...)`. This would retain the same advantages e.g not requiring to escape `/`. However it would also still retain the same issues, such as still looking potentially visually noisy as an argument, and having suboptimal behavior for parenthesis balancing. It is also not clear why regex literals would deserve such privileged syntax. + +### Reusing string literal syntax + +Instead of supporting a first-class literal kind for regular expressions, we could instead allow users to write a regular expression in a string literal, and parse, diagnose, and generate the appropriate code when it's coerced to an `ExpressibleByRegexLiteral` conforming type. + +```swift +let regex: Regex = "([[:alpha:]]\w*) = ([0-9A-F]+)" +``` -We could choose to use double quotes instead of single quotes. This would be similar in appearance to string literals, however it could be argued that regex literals are distinct from string literals in that they introduce their own specific language to parse. As such, regex literals are more like "program literals" than "data literals", and the use of single quote instead of double quote could express this difference. +However we decided against this because: -### Single letter `r'...'` +- We would not be able to easily apply custom syntax highlighting for the regex syntax. +- It would require an `ExpressibleByRegexLiteral` contextual type to be treated as a regex, otherwise it would be defaulted to `String`, which may be undesired. +- In an overloaded context it may be ambiguous or unclear whether a string literal is meant to be interpreted as a literal string or regex. +- Regex escape sequences aren't currently compatible with string literal escape sequence rules, e.g `\w` is currently illegal in a string literal. +- It wouldn't be compatible with other string literal features such as interpolations. -We could choose to shorten the literal prefix to just `r`. However this could potentially be confused to mean "raw", especially as Python uses this syntax for raw strings. The syntax `re'...'` could also set the precedent for a 2 letter namespace for future literals. +### No custom literal -**TODO: Add the other alternatives e.g `#regex(...)`** +Instead of adding a custom regex literal, we could require users to explicitly write `Regex(compiling: "[abc]+")`. This would however lose all the benefits of parsing the literal at compile time, meaning that parse errors will instead be diagnosed at runtime, and no source tooling support (e.g syntax highlighting, refactoring actions) would be available. [SE-0168]: https://github.com/apple/swift-evolution/blob/main/proposals/0168-multi-line-string-literals.md [SE-0200]: https://github.com/apple/swift-evolution/blob/main/proposals/0200-raw-string-escaping.md From be7a8022dd54990e984550a59699fe4021ac05db Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 23 Mar 2022 17:31:19 +0000 Subject: [PATCH 012/133] Fix headings --- Documentation/Evolution/DelimiterSyntax.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index b45872337..fd66d11cf 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -215,13 +215,13 @@ This would be a double quoted version of `re'...'`, more similar to string liter This would be a slightly shorter version of `re'...'`. While it's more concise, it could potentially be confused to mean "raw", especially as Python uses this syntax for raw strings. -#### Single quotes `'...'` +### Single quotes `'...'` This would be an even more concise version of `re'...'` that drops the prefix entirely. However, given how close it is to string literal syntax, it may not be entirely clear to users that `'...'` denotes a regular expression as opposed to some different form of string literal (e.g some form of character literal, or a string literal with different escaping rules). We could help distinguish it from a string literal by requiring e.g `'/.../'`, though it may not be clear that the `/` characters are part of the delimiters rather than part of the literal. Additionally, this would potentially rule out the use of `'...'` as a future literal kind. -#### Magic literal `#regex(...)` +### Magic literal `#regex(...)` We could opt for for a more explicitly spelled out literal syntax such as `#regex(...)`. This is an even more heavyweight option, similar to `#selector(...)`. As such, it may be considered syntactically noisy as e.g a function argument `str.match(#regex([abc]+))` vs `str.match(/[abc]+/)`. @@ -231,7 +231,7 @@ We could avoid the parenthesis balancing issue by requiring an additional intern It should also be noted that `#regex(...)` would introduce a syntactic inconsistency where the argument of a `#literal(...)` is no longer necessarily valid Swift syntax, despite being written in the form of an argument. -#### Shortened magic literal `#(...)` +### Shortened magic literal `#(...)` We could reduce the visual weight of `#regex(...)` by only requiring `#(...)`. This would retain the same advantages e.g not requiring to escape `/`. However it would also still retain the same issues, such as still looking potentially visually noisy as an argument, and having suboptimal behavior for parenthesis balancing. It is also not clear why regex literals would deserve such privileged syntax. From 06c2b28f53eeb2b13eccb89d2f3635d363f4fc90 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 23 Mar 2022 17:38:13 +0000 Subject: [PATCH 013/133] Tweak phrasing --- Documentation/Evolution/DelimiterSyntax.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index fd66d11cf..9455dd0d0 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -223,7 +223,7 @@ We could help distinguish it from a string literal by requiring e.g `'/.../'`, t ### Magic literal `#regex(...)` -We could opt for for a more explicitly spelled out literal syntax such as `#regex(...)`. This is an even more heavyweight option, similar to `#selector(...)`. As such, it may be considered syntactically noisy as e.g a function argument `str.match(#regex([abc]+))` vs `str.match(/[abc]+/)`. +We could opt for for a more explicitly spelled out literal syntax such as `#regex(...)`. This is a more heavyweight option, similar to `#selector(...)`. As such, it may be considered syntactically noisy as e.g a function argument `str.match(#regex([abc]+))` vs `str.match(/[abc]+/)`. Such a syntax would require the containing regex to correctly balance capture group parentheses, otherwise the rest of the line might be incorrectly considered a regex. This could place additional cognitive burden on the user, and may lead to an awkward typing experience. For example, if the user is editing a previously written regex, the syntax highlighting for the rest of the line may change, and unhelpful spurious errors may be reported. With a different delimiter, the compiler would be able to detect and better diagnose unbalanced parentheses in the regex. @@ -233,14 +233,14 @@ It should also be noted that `#regex(...)` would introduce a syntactic inconsist ### Shortened magic literal `#(...)` -We could reduce the visual weight of `#regex(...)` by only requiring `#(...)`. This would retain the same advantages e.g not requiring to escape `/`. However it would also still retain the same issues, such as still looking potentially visually noisy as an argument, and having suboptimal behavior for parenthesis balancing. It is also not clear why regex literals would deserve such privileged syntax. +We could reduce the visual weight of `#regex(...)` by only requiring `#(...)`. However it would still retain the same issues, such as still looking potentially visually noisy as an argument, and having suboptimal behavior for parenthesis balancing. It is also not clear why regex literals would deserve such privileged syntax. ### Reusing string literal syntax Instead of supporting a first-class literal kind for regular expressions, we could instead allow users to write a regular expression in a string literal, and parse, diagnose, and generate the appropriate code when it's coerced to an `ExpressibleByRegexLiteral` conforming type. ```swift -let regex: Regex = "([[:alpha:]]\w*) = ([0-9A-F]+)" +let regex: Regex = #"([[:alpha:]]\w*) = ([0-9A-F]+)"# ``` However we decided against this because: @@ -248,7 +248,7 @@ However we decided against this because: - We would not be able to easily apply custom syntax highlighting for the regex syntax. - It would require an `ExpressibleByRegexLiteral` contextual type to be treated as a regex, otherwise it would be defaulted to `String`, which may be undesired. - In an overloaded context it may be ambiguous or unclear whether a string literal is meant to be interpreted as a literal string or regex. -- Regex escape sequences aren't currently compatible with string literal escape sequence rules, e.g `\w` is currently illegal in a string literal. +- Regex-specific escape sequences such as `\w` would likely require the use of raw string syntax `#"..."#`, as they are otherwise invalid in a string literal. - It wouldn't be compatible with other string literal features such as interpolations. ### No custom literal From 91a93a89ecc1d7cb80db5c626a7648c71752ebb7 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 23 Mar 2022 20:22:17 +0000 Subject: [PATCH 014/133] Small tweaks --- Documentation/Evolution/DelimiterSyntax.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 9455dd0d0..e1d3fc65a 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -16,14 +16,14 @@ A regular expression literal will be introduced using `/.../` delimiters, within which the compiler will parse a regular expression (the details of which are outlined in [the Regex Syntax pitch][internal-syntax]): -``` +```swift // Matches " = ", extracting the identifier and hex number let regex = /([[:alpha:]]\w*) = ([0-9A-F]+)/ ``` -Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternative choices). Due to its existing use in comment syntax and operators, there are some syntactic ambiguities to consider. While there are quite a few cases to consider, we do not feel that the impact of any individual case is particularly high. +Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternatives). Their ubiquity and familiarity makes them a compelling choice for Swift. -**TODO: Do we want to present a stronger argument for `/.../`?** +Due to the existing use of `/` in comment syntax and operators, there are some syntactic ambiguities to consider. While there are quite a few cases to consider, we do not feel that the impact of any individual case is sufficient to disqualify the syntax. **TODO: Anything else we want to say here before segueing into the massive list?** @@ -182,7 +182,7 @@ Additionally, introducing this syntax would introduce an inconsistency with raw ## Future Directions -**TODO: What do we want to say here?** +**TODO: What do we want to say here? Talk about raw and multiline? Don't really have a good option for the latter tho** ## Alternatives Considered @@ -190,14 +190,14 @@ Additionally, introducing this syntax would introduce an inconsistency with raw We could choose to use `re'...'` delimiters, for example: -``` +```swift // Matches " = ", extracting the identifier and hex number let regex = re'([[:alpha:]]\w*) = ([0-9A-F]+)' ``` The use of two letter prefix could potentially be used as a namespace for future literal types. However, it is unusual for a Swift literal to be prefixed in this way. -**TODO: Fill in reasons why not to pick this** +**TODO: Any other reasons why not to pick this?** **TODO: Mention that it nicely extends to raw and multiline?** @@ -225,7 +225,7 @@ We could help distinguish it from a string literal by requiring e.g `'/.../'`, t We could opt for for a more explicitly spelled out literal syntax such as `#regex(...)`. This is a more heavyweight option, similar to `#selector(...)`. As such, it may be considered syntactically noisy as e.g a function argument `str.match(#regex([abc]+))` vs `str.match(/[abc]+/)`. -Such a syntax would require the containing regex to correctly balance capture group parentheses, otherwise the rest of the line might be incorrectly considered a regex. This could place additional cognitive burden on the user, and may lead to an awkward typing experience. For example, if the user is editing a previously written regex, the syntax highlighting for the rest of the line may change, and unhelpful spurious errors may be reported. With a different delimiter, the compiler would be able to detect and better diagnose unbalanced parentheses in the regex. +Such a syntax would require the containing regex to correctly balance parentheses for groups, otherwise the rest of the line might be incorrectly considered a regex. This could place additional cognitive burden on the user, and may lead to an awkward typing experience. For example, if the user is editing a previously written regex, the syntax highlighting for the rest of the line may change, and unhelpful spurious errors may be reported. With a different delimiter, the compiler would be able to detect and better diagnose unbalanced parentheses in the regex. We could avoid the parenthesis balancing issue by requiring an additional internal delimiter such as `#regex(/.../)`. However it is even more heavyweight, and it may be unclear that `/` is part of the delimiter rather than part of the literal. Alternatively, we could replace the internal delimiter with another character such as ```#regex`...` ```, `#regex{...}`, or `#regex/.../`. However those would be inconsistent with the existing `#literal(...)` syntax and the first two would overload the existing meanings for the ``` `` ``` and `{}` delimiters. From c0e3befca172b1d1d07dc0b357d86cadef02bdef Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 23 Mar 2022 20:25:53 +0000 Subject: [PATCH 015/133] Tweak --- Documentation/Evolution/DelimiterSyntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index e1d3fc65a..e2d53f280 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -112,7 +112,7 @@ Postfix `/` operators would be okay, as they'd only be treated as regex literal #### Prefix operators containing `/` -Prefix operators *containing* `/` (not just at the start) would likely need banning too, in order to allow prefix operators to be used with regex literals in an unambiguous way, e.g: +Prefix operators *containing* `/` (not just at the start) need banning too, in order to allow prefix operators to be used with regex literals in an unambiguous way, e.g: ```swift let x = !/y / .foo() From 298092c5bd3c86870998bdca436cf174b031d4c5 Mon Sep 17 00:00:00 2001 From: David Ewing Date: Wed, 23 Mar 2022 22:21:31 -0600 Subject: [PATCH 016/133] Flesh things out a bit more. Initial bits for the Intro and Motivation. Split out Proposed solution from Detailed design. Parallelize the structure a bit better. --- Documentation/Evolution/DelimiterSyntax.md | 75 ++++++++++++---------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index e2d53f280..8feed983e 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -1,20 +1,27 @@ -# Regular Expression Literal Delimiters +# Regex Literal Delimiters - Authors: Hamish Knight, Michael Ilseman, David Ewing ## Introduction -**TODO** +This proposal introduces regex literals to Swift source code. The proposed syntax mirrors literals in other programing languages such as Perl, JavaScript and Ruby. As in those languages, literals are delimited with the `/` character: -**TODO: Motivation for regex literals in the first place? Or is that a given?** +```swift +let re = /[0-9]+/ +``` + +## Motivation -**TODO: Overview of regex literals in other languages?** +This proposal helps complete the story told in [Regex Type and Overview][regex-type] and [elsewhere][pitch-status]. Literals are compiled directly, allowing errors to be found at compile time, rather than at run time. Using a literal also allows editors to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see [Regex builder DSL][regex-dsl]). It would be difficult to support all of this if regexes could only be defined inside a string. -## Detailed Design + +## Proposed solution **TODO: Say that this is Swift 6 syntax only, `#/.../#` would be 5.7 syntax** -A regular expression literal will be introduced using `/.../` delimiters, within which the compiler will parse a regular expression (the details of which are outlined in [the Regex Syntax pitch][internal-syntax]): +**TODO: But is it?** + +A regex literal will be introduced using `/.../` delimiters, within which the compiler will parse a regular expression (the details of which are outlined in [the Regex Syntax pitch][internal-syntax]): ```swift // Matches " = ", extracting the identifier and hex number @@ -25,21 +32,21 @@ Forward slashes are a regex term of art, and are used as the delimiters for rege Due to the existing use of `/` in comment syntax and operators, there are some syntactic ambiguities to consider. While there are quite a few cases to consider, we do not feel that the impact of any individual case is sufficient to disqualify the syntax. -**TODO: Anything else we want to say here before segueing into the massive list?** +## Detailed design -### Parsing ambiguities +Choice of `/` as the regex literal delimiter requires a number of ambiguities to be resolved. And it requires some existing features of the language to be disallowed. -The obvious parsing ambiguity with `/.../` delimiters is with comment syntaxes. +### Ambiguities with comment syntax -- An empty regex literal would conflict with line comment syntax `//`. But this isn't a particularly useful thing to express, and can therefore be disallowed without significant impact. +Perhaps the most obvious parsing ambiguity with `/.../` delimiters is with comment syntax. -- The obvious choice for a multi-line regular expression literal would be to use `///` delimiters, in accordance with the precedent set by multi-line string literals `"""`. A different multi-line delimiter would be needed, with no obvious choice. +- An empty regex literal would conflict with line comment syntax `//`. But an empty regex isn't a particularly useful thing to express, and can be disallowed without significant impact. - There is a conflict with block comment syntax, when surrounding a regex literal ending with `*`, for example: ```swift /* - let regex = /x*/ + let regex = /[0-9]*/ */ ``` @@ -47,7 +54,10 @@ The obvious parsing ambiguity with `/.../` delimiters is with comment syntaxes. - Block comment syntax also means that a regex literal would not be able to start with the `*` character, however this is less of a concern as it would not be valid regex syntax. -- Finally, there would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required `x + /y/` for regex literal interpretation. + +### Ambiguity with infix operators + +There would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required `x + /y/` for regex literal interpretation. ### Regex syntax limitations @@ -163,12 +173,22 @@ This takes advantage of the fact that a regex literal will not be parsed if the -### Editor Considerations -**TODO: Rewrite now that `/.../` is the syntax being pitched?** +## Future Directions + +### Raw literals + +The obvious choice here would follow string literals and use `#/.../#`. + +### Multi-line literals + +The obvious choice for a multi-line regex literal would be to use `///` delimiters, in accordance with the precedent set by multi-line string literals `"""`. But this signifies a (documentation) comment, so a different multi-line delimiter would be needed, with no obvious choice. However, it's not clear that we need multi-line regex literals. The existing literals can be used inside a regex builder DSL. -As described above, there would be a lot involved in handling the parsing ambiguities with `/.../` delimiters. It's one thing to do this in the compiler. But the language also has to be understood by a plethora of source code editors. Those editors either need encode all those ambiguities, or they need to provide a "best effort" at handling the most common cases. It's all too common for editors to take the "best effort" route. There's a long history of complaints with editors that don't completely support a language's features. And indeed, there's plenty of history of editors that don't correctly support regular expression literals in other languages. By choosing a literal that is easily parsed, we should avoid seeing those complaints regarding Swift. +### Regex extended syntax +Allowing non-semantic whitespace and other features of the extended syntax would be highly desired, with no obvious choice for a literal. Perhaps the need is also lessened by the ability to use regex literals inside the regex builder DSL. + +## Alternatives Considered ### Pound slash `#/.../#` @@ -180,12 +200,6 @@ However this option would also have the same block comment issue as `/.../` wher Additionally, introducing this syntax would introduce an inconsistency with raw string literal syntax, as `#/.../#` on its own would not treat backslashes as literal, unlike `#"..."#`. If raw regex syntax were implemented, it would start at `##/.../##`. With raw strings, escape sequences must use the same number of `#`s as the delimiter, e.g `#"\#n"#` for a newline. However for raw regex literals it would be one fewer `#` than the delimiter e.g `##/\#n/##`. -## Future Directions - -**TODO: What do we want to say here? Talk about raw and multiline? Don't really have a good option for the latter tho** - -## Alternatives Considered - ### Prefixed quote `re'...'` We could choose to use `re'...'` delimiters, for example: @@ -195,17 +209,9 @@ We could choose to use `re'...'` delimiters, for example: let regex = re'([[:alpha:]]\w*) = ([0-9A-F]+)' ``` -The use of two letter prefix could potentially be used as a namespace for future literal types. However, it is unusual for a Swift literal to be prefixed in this way. - -**TODO: Any other reasons why not to pick this?** - -**TODO: Mention that it nicely extends to raw and multiline?** - -#### Regex syntax limitations - -There are a few items of regex grammar that use the single quote character as a metacharacter. These include named group definitions and references such as `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, as well as callout syntax `(?C'arg')`. The use of a single quote conflicts with the `re'...'` delimiter as it will be considered the end of the literal. Fortunately, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`, and `(?C"arg")`. +The use of two letter prefix could potentially be used as a namespace for future literal types. It would also have obvious extensions to raw and multi-line literals using `re#'...'#` and `re'''...'''` respectively. However, it is unusual for a Swift literal to be prefixed in this way. We also feel that its similarity to a string literal might have users confuse it with a raw string literal. -As such, the single quote variants of the syntax would be considered invalid in a `re'...'` literal, and users must use the alternative syntax instead. If a raw variant of the syntax `re#'...'#` of the syntax is later added, that may also be used. In order to improve diagnostic behavior, the compiler would attempt to scan ahead when encountering the ending sequences `(?`, `(?(`, `\g`, `\k` and `(?C`. This would enable a more accurate error to be emitted that suggests the alternative syntax. +Also, there are a few items of regex grammar that use the single quote character as a metacharacter. These include named group definitions and references such as `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, as well as callout syntax `(?C'arg')`. The use of a single quote conflicts with the `re'...'` delimiter as it will be considered the end of the literal. However, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`, and `(?C"arg")`. Those could be required instead. If a raw regex literal were later added, the single quote syntax could also be used. ### Prefixed double quote `re"...."` @@ -245,7 +251,7 @@ let regex: Regex = #"([[:alpha:]]\w*) = ([0-9A-F]+)"# However we decided against this because: -- We would not be able to easily apply custom syntax highlighting for the regex syntax. +- We would not be able to easily apply custom syntax highlighting and other editor features for the regex syntax. - It would require an `ExpressibleByRegexLiteral` contextual type to be treated as a regex, otherwise it would be defaulted to `String`, which may be undesired. - In an overloaded context it may be ambiguous or unclear whether a string literal is meant to be interpreted as a literal string or regex. - Regex-specific escape sequences such as `\w` would likely require the use of raw string syntax `#"..."#`, as they are otherwise invalid in a string literal. @@ -258,3 +264,6 @@ Instead of adding a custom regex literal, we could require users to explicitly w [SE-0168]: https://github.com/apple/swift-evolution/blob/main/proposals/0168-multi-line-string-literals.md [SE-0200]: https://github.com/apple/swift-evolution/blob/main/proposals/0200-raw-string-escaping.md [internal-syntax]: https://forums.swift.org/t/pitch-regex-syntax/55711 +[regex-type]: https://forums.swift.org/t/pitch-regex-type-and-overview/56029 +[pitch-status]: https://github.com/apple/swift-experimental-string-processing/issues/107 +[regex-dsl]: https://forums.swift.org/t/pitch-regex-builder-dsl/56007 \ No newline at end of file From 1ebefa1b4a4dd304948e54e66131603a8ac54eb2 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 24 Mar 2022 14:56:45 +0000 Subject: [PATCH 017/133] Expand out disclosure triangles, and other tweaks --- Documentation/Evolution/DelimiterSyntax.md | 52 ++++++++++------------ 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 8feed983e..da889082b 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -21,7 +21,7 @@ This proposal helps complete the story told in [Regex Type and Overview][regex-t **TODO: But is it?** -A regex literal will be introduced using `/.../` delimiters, within which the compiler will parse a regular expression (the details of which are outlined in [the Regex Syntax pitch][internal-syntax]): +A regex literal will be introduced using `/.../` delimiters, within which the compiler will parse a regex (the details of which are outlined in [the Regex Syntax pitch][internal-syntax]): ```swift // Matches " = ", extracting the identifier and hex number @@ -34,7 +34,7 @@ Due to the existing use of `/` in comment syntax and operators, there are some s ## Detailed design -Choice of `/` as the regex literal delimiter requires a number of ambiguities to be resolved. And it requires some existing features of the language to be disallowed. +Choosing `/` as the regex literal delimiter requires a number of ambiguities to be resolved. It also requires a couple of source breaking language changes to be introduced in a new language mode. ### Ambiguities with comment syntax @@ -50,7 +50,7 @@ Perhaps the most obvious parsing ambiguity with `/.../` delimiters is with comme */ ``` - In this case, the block comment would prematurely end on the second line, rather than extending all the way to the third line as the user would expect. This is already an issue today with `*/` in a string literal, however it is much more likely to occur in a regular expression given the prevalence of the `*` quantifier. + In this case, the block comment would prematurely end on the second line, rather than extending all the way to the third line as the user would expect. This is already an issue today with `*/` in a string literal, though it is more likely to occur in a regex given the prevalence of the `*` quantifier. This issue can be avoided in many cases by using line comment syntax `//` instead, which it should be noted is the syntax that Xcode uses when commenting out multiple lines. - Block comment syntax also means that a regex literal would not be able to start with the `*` character, however this is less of a concern as it would not be valid regex syntax. @@ -63,7 +63,7 @@ There would be a minor ambiguity with infix operators used with regex literals. In order to help avoid further parsing ambiguities, a regex literal will not be parsed if it starts with a space, tab, or `)` character. Though the latter is already invalid regex syntax. -
Rationale +#### Rationale This is due to 2 main ambiguities. The first of which arises when a `/.../` regex literal starts a new line. This is particularly problematic for result builders, where we expect it to be frequently used, for example: @@ -75,7 +75,7 @@ Builder { } ``` -This is parsed as a single operator chain, however it is likely the user is expecting a regex literal. To resolve this ambiguity, a regex literal may not start with a space or tab character. This takes advantage of the fact that infix operators require consistent spacing on either side. +This is parsed as a single operator chain, however it is likely the user is expecting a regex literal. To resolve this ambiguity, a regex literal may not start with a space or tab character. The above therefore remains an operator chain. This takes advantage of the fact that infix operators require consistent spacing on either side. If a space or tab is needed as the first character, it must be escaped, e.g: @@ -87,7 +87,7 @@ Builder { } ``` -The second ambiguity arises with Swift's ability to pass an unapplied operator reference as an argument to a function, for example: +The second ambiguity arises with Swift's ability to pass an unapplied operator reference as an argument to a function or subscript, for example: ```swift let arr: [Double] = [2, 3, 4] @@ -98,37 +98,31 @@ The `/` in the call to `reduce` is in a valid expression context, and as such co It should be noted that this only mitigates the issue, as it does not handle the case where the next character is a comma or right square bracket. These cases are explored further in the following section. -
- ### Language changes required In addition to ambiguities listed above, there are also some parsing ambiguities that would require the following language changes in Swift 6 mode: - Deprecation of prefix operators containing the `/` character. - Parsing `/,` and `/]` as the start of a regex literal if a closing `/` is found, rather than an unapplied operator in an argument list. For example, `fn(/, /)` becomes a regex literal rather than 2 unapplied operator arguments. - -
Rationale -#### Prefix operators starting with `/` +#### Prefix operators containing `/` -We'd need to ban prefix operators starting with `/`, to avoid ambiguity with cases such as: +We need to ban prefix operators starting with `/`, to avoid ambiguity with cases such as: ```swift let x = /0; let y = 1/ let z = /^x^/ ``` - -Postfix `/` operators would be okay, as they'd only be treated as regex literal delimiters if we were already trying to lex as a regex literal. -#### Prefix operators containing `/` - -Prefix operators *containing* `/` (not just at the start) need banning too, in order to allow prefix operators to be used with regex literals in an unambiguous way, e.g: +Prefix operators containing `/` more generally also need banning, in order to allow prefix operators to be used with regex literals in an unambiguous way, e.g: ```swift let x = !/y / .foo() ``` - -Otherwise it would be interpreted as the prefix operator `!/` by default, and require parens `!(/y /)` for regex parsing. + +Today, this is interpreted as the prefix operator `!/` on `y`. With the banning of prefix operators containing `/`, it becomes prefix `!` on a regex literal, with a member access `.foo`. + +Postfix `/` operators do not require banning, as they'd only be treated as regex literal delimiters if we are already trying to lex as a regex literal. #### `/,` and `/]` as regex literal openings @@ -156,8 +150,6 @@ func baz(_ x: S) -> Int { `foo(/, /)` is currently parsed as 2 unapplied operator arguments. `bar(/, 2) + bar(/, 3)` is currently parsed as two independent calls that each take an unapplied `/` operator reference. Both of these would become regex literals arguments, `/, /` and `/, 2) + bar(/` respectively (though the latter would produce a regex error). -**TODO: Do we want to talk about a heuristic that looks for unbalanced parens? I'm kind of hesitant to implement that, as it would have edge cases and might screw with regex errors that should be diagnosed as invalid regex, rather than some cryptic Swift syntactic error. Which would also make it harder to explain to users.** - To disambiguate these cases, users will need to surround at least the opening `/` with parentheses, e.g: ```swift @@ -180,6 +172,8 @@ This takes advantage of the fact that a regex literal will not be parsed if the The obvious choice here would follow string literals and use `#/.../#`. +**TODO: What backslash rules do we want?** + ### Multi-line literals The obvious choice for a multi-line regex literal would be to use `///` delimiters, in accordance with the precedent set by multi-line string literals `"""`. But this signifies a (documentation) comment, so a different multi-line delimiter would be needed, with no obvious choice. However, it's not clear that we need multi-line regex literals. The existing literals can be used inside a regex builder DSL. @@ -192,7 +186,7 @@ Allowing non-semantic whitespace and other features of the extended syntax would ### Pound slash `#/.../#` -**TODO: This needs to be rewritten to say that it's a transition syntax** +**TODO: This needs to be rewritten to say that it's a potential transition syntax** This would be less syntactically ambiguous than `/.../`, while retaining some of the term-of-art familiarity. It would also provide a natural path through which to introduce `/.../` in a new language mode, as users could drop the `#` characters once they upgrade. @@ -211,11 +205,11 @@ let regex = re'([[:alpha:]]\w*) = ([0-9A-F]+)' The use of two letter prefix could potentially be used as a namespace for future literal types. It would also have obvious extensions to raw and multi-line literals using `re#'...'#` and `re'''...'''` respectively. However, it is unusual for a Swift literal to be prefixed in this way. We also feel that its similarity to a string literal might have users confuse it with a raw string literal. -Also, there are a few items of regex grammar that use the single quote character as a metacharacter. These include named group definitions and references such as `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, as well as callout syntax `(?C'arg')`. The use of a single quote conflicts with the `re'...'` delimiter as it will be considered the end of the literal. However, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`, and `(?C"arg")`. Those could be required instead. If a raw regex literal were later added, the single quote syntax could also be used. +Also, there are a few items of regex grammar that use the single quote character as a metacharacter. These include named group definitions and references such as `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, as well as callout syntax `(?C'arg')`. The use of a single quote conflicts with the `re'...'` delimiter as it will be considered the end of the literal. However, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`, and `(?C"arg")`. Those could be required instead. A raw regex literal syntax e.g `re#'...'#` would also avoid this issue. ### Prefixed double quote `re"...."` -This would be a double quoted version of `re'...'`, more similar to string literal syntax. This has the advantage that single quote regex syntax e.g `(?'name')` would continue to work without requiring the use of the alternative syntax or "raw syntax" delimiters. However it could be argued that regex literals are distinct from string literals in that they introduce their own specific language to parse. As such, regex literals are more like "program literals" than "data literals", and the use of single quote instead of double quote may be useful in expressing this difference. +This would be a double quoted version of `re'...'`, more similar to string literal syntax. This has the advantage that single quote regex syntax e.g `(?'name')` would continue to work without requiring the use of the alternative syntax or raw literal syntax. However it could be argued that regex literals are distinct from string literals in that they introduce their own specific language to parse. As such, regex literals are more like "program literals" than "data literals", and the use of single quote instead of double quote may be useful in expressing this difference. ### Single letter prefixed quote `r'...'` @@ -223,7 +217,7 @@ This would be a slightly shorter version of `re'...'`. While it's more concise, ### Single quotes `'...'` -This would be an even more concise version of `re'...'` that drops the prefix entirely. However, given how close it is to string literal syntax, it may not be entirely clear to users that `'...'` denotes a regular expression as opposed to some different form of string literal (e.g some form of character literal, or a string literal with different escaping rules). +This would be an even more concise version of `re'...'` that drops the prefix entirely. However, given how close it is to string literal syntax, it may not be entirely clear to users that `'...'` denotes a regex as opposed to some different form of string literal (e.g some form of character literal, or a string literal with different escaping rules). We could help distinguish it from a string literal by requiring e.g `'/.../'`, though it may not be clear that the `/` characters are part of the delimiters rather than part of the literal. Additionally, this would potentially rule out the use of `'...'` as a future literal kind. @@ -233,7 +227,7 @@ We could opt for for a more explicitly spelled out literal syntax such as `#rege Such a syntax would require the containing regex to correctly balance parentheses for groups, otherwise the rest of the line might be incorrectly considered a regex. This could place additional cognitive burden on the user, and may lead to an awkward typing experience. For example, if the user is editing a previously written regex, the syntax highlighting for the rest of the line may change, and unhelpful spurious errors may be reported. With a different delimiter, the compiler would be able to detect and better diagnose unbalanced parentheses in the regex. -We could avoid the parenthesis balancing issue by requiring an additional internal delimiter such as `#regex(/.../)`. However it is even more heavyweight, and it may be unclear that `/` is part of the delimiter rather than part of the literal. Alternatively, we could replace the internal delimiter with another character such as ```#regex`...` ```, `#regex{...}`, or `#regex/.../`. However those would be inconsistent with the existing `#literal(...)` syntax and the first two would overload the existing meanings for the ``` `` ``` and `{}` delimiters. +We could avoid the parenthesis balancing issue by requiring an additional internal delimiter such as `#regex(/.../)`. However this is even more heavyweight, and it may be unclear that `/` is part of the delimiter rather than part of an argument. Alternatively, we could replace the internal delimiter with another character such as ```#regex`...` ```, `#regex{...}`, or `#regex/.../`. However those would be inconsistent with the existing `#literal(...)` syntax and the first two would overload the existing meanings for the ``` `` ``` and `{}` delimiters. It should also be noted that `#regex(...)` would introduce a syntactic inconsistency where the argument of a `#literal(...)` is no longer necessarily valid Swift syntax, despite being written in the form of an argument. @@ -243,7 +237,7 @@ We could reduce the visual weight of `#regex(...)` by only requiring `#(...)`. H ### Reusing string literal syntax -Instead of supporting a first-class literal kind for regular expressions, we could instead allow users to write a regular expression in a string literal, and parse, diagnose, and generate the appropriate code when it's coerced to an `ExpressibleByRegexLiteral` conforming type. +Instead of supporting a first-class literal kind for regex, we could instead allow users to write a regex in a string literal, and parse, diagnose, and generate the appropriate code when it's coerced to the `Regex` type. ```swift let regex: Regex = #"([[:alpha:]]\w*) = ([0-9A-F]+)"# @@ -252,7 +246,7 @@ let regex: Regex = #"([[:alpha:]]\w*) = ([0-9A-F]+)"# However we decided against this because: - We would not be able to easily apply custom syntax highlighting and other editor features for the regex syntax. -- It would require an `ExpressibleByRegexLiteral` contextual type to be treated as a regex, otherwise it would be defaulted to `String`, which may be undesired. +- It would require a `Regex` contextual type to be treated as a regex, otherwise it would be defaulted to `String`, which may be undesired. - In an overloaded context it may be ambiguous or unclear whether a string literal is meant to be interpreted as a literal string or regex. - Regex-specific escape sequences such as `\w` would likely require the use of raw string syntax `#"..."#`, as they are otherwise invalid in a string literal. - It wouldn't be compatible with other string literal features such as interpolations. @@ -266,4 +260,4 @@ Instead of adding a custom regex literal, we could require users to explicitly w [internal-syntax]: https://forums.swift.org/t/pitch-regex-syntax/55711 [regex-type]: https://forums.swift.org/t/pitch-regex-type-and-overview/56029 [pitch-status]: https://github.com/apple/swift-experimental-string-processing/issues/107 -[regex-dsl]: https://forums.swift.org/t/pitch-regex-builder-dsl/56007 \ No newline at end of file +[regex-dsl]: https://forums.swift.org/t/pitch-regex-builder-dsl/56007 From 811bfcb7255c10410bd93393e32c8006c7b25535 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 24 Mar 2022 15:44:54 +0000 Subject: [PATCH 018/133] Generalize discussion on language mode --- Documentation/Evolution/DelimiterSyntax.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index da889082b..7c9cb2a6a 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -17,10 +17,6 @@ This proposal helps complete the story told in [Regex Type and Overview][regex-t ## Proposed solution -**TODO: Say that this is Swift 6 syntax only, `#/.../#` would be 5.7 syntax** - -**TODO: But is it?** - A regex literal will be introduced using `/.../` delimiters, within which the compiler will parse a regex (the details of which are outlined in [the Regex Syntax pitch][internal-syntax]): ```swift @@ -32,6 +28,8 @@ Forward slashes are a regex term of art, and are used as the delimiters for rege Due to the existing use of `/` in comment syntax and operators, there are some syntactic ambiguities to consider. While there are quite a few cases to consider, we do not feel that the impact of any individual case is sufficient to disqualify the syntax. +Some of these ambiguities require a couple of source breaking language changes, and as such the `/.../` syntax will require upgrading to a new language mode in order to use. + ## Detailed design Choosing `/` as the regex literal delimiter requires a number of ambiguities to be resolved. It also requires a couple of source breaking language changes to be introduced in a new language mode. @@ -186,13 +184,13 @@ Allowing non-semantic whitespace and other features of the extended syntax would ### Pound slash `#/.../#` -**TODO: This needs to be rewritten to say that it's a potential transition syntax** +This is a less syntactically ambiguous version of `/.../` that retains some of the term-of-art familiarity. It could potentially provide a natural path through which to introduce `/.../` in a new language mode, as users could drop the `#` characters once they upgrade. -This would be less syntactically ambiguous than `/.../`, while retaining some of the term-of-art familiarity. It would also provide a natural path through which to introduce `/.../` in a new language mode, as users could drop the `#` characters once they upgrade. +However, introducing this as non-raw regex literal syntax would introduce an inconsistency with raw string literal syntax, as `#/.../#` on its own would not treat backslashes as literal, unlike `#"..."#`. If raw regex syntax were added, they would likely start at `##/.../##`. With raw strings, escape sequences must use the same number of `#`s as the delimiter, e.g `#"\#n"#` for a newline. However for raw regex literals it would be one fewer `#` than the delimiter e.g `##/\#n/##`. -However this option would also have the same block comment issue as `/.../` where e.g `#/x*/#` nested inside a block comment would prematurely end. Similarly, it's not clear how a multi-line version of the literal would be spelled. +**TODO: What backslash rules do we want?** -Additionally, introducing this syntax would introduce an inconsistency with raw string literal syntax, as `#/.../#` on its own would not treat backslashes as literal, unlike `#"..."#`. If raw regex syntax were implemented, it would start at `##/.../##`. With raw strings, escape sequences must use the same number of `#`s as the delimiter, e.g `#"\#n"#` for a newline. However for raw regex literals it would be one fewer `#` than the delimiter e.g `##/\#n/##`. +It should also be noted that this option has the same block comment issue as `/.../` where e.g `#/[0-9]*/#` nested inside a block comment would prematurely end. Similarly, it's not clear how a multi-line version of the literal would be spelled. ### Prefixed quote `re'...'` From 70be0064db5fde6327954b9e13738a9fef7112a1 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Fri, 25 Mar 2022 12:50:16 +0000 Subject: [PATCH 019/133] Expand some prose --- Documentation/Evolution/DelimiterSyntax.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 7c9cb2a6a..4afd3af96 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -1,4 +1,4 @@ -# Regex Literal Delimiters +# Regex Literals - Authors: Hamish Knight, Michael Ilseman, David Ewing @@ -24,11 +24,11 @@ A regex literal will be introduced using `/.../` delimiters, within which the co let regex = /([[:alpha:]]\w*) = ([0-9A-F]+)/ ``` -Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternatives). Their ubiquity and familiarity makes them a compelling choice for Swift. +The above regex literal will be inferred to be [the regex type][regex-type] `Regex<(Substring, Substring, Substring)>`, where the capture types have been automatically inferred. Errors in the regex will be diagnosed by the compiler. -Due to the existing use of `/` in comment syntax and operators, there are some syntactic ambiguities to consider. While there are quite a few cases to consider, we do not feel that the impact of any individual case is sufficient to disqualify the syntax. +Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternatives). Their ubiquity and familiarity makes them a compelling choice for Swift. -Some of these ambiguities require a couple of source breaking language changes, and as such the `/.../` syntax will require upgrading to a new language mode in order to use. +Due to the existing use of `/` in comment syntax and operators, there are some syntactic ambiguities to consider. While there are quite a few cases to consider, we do not feel that the impact of any individual case is sufficient to disqualify the syntax. Some of these ambiguities require a couple of source breaking language changes, and as such the `/.../` syntax will require upgrading to a new language mode in order to use. ## Detailed design @@ -182,11 +182,13 @@ Allowing non-semantic whitespace and other features of the extended syntax would ## Alternatives Considered +Given the fact that `/` is an existing term of art for regular expressions, we feel it should be the preferred delimiter syntax. While it has some syntactic ambiguities, we do not feel that they are sufficient to disqualify the syntax. To evaluate this trade-off, below is a list of alternative delimiters that would not have the same ambiguities. + ### Pound slash `#/.../#` This is a less syntactically ambiguous version of `/.../` that retains some of the term-of-art familiarity. It could potentially provide a natural path through which to introduce `/.../` in a new language mode, as users could drop the `#` characters once they upgrade. -However, introducing this as non-raw regex literal syntax would introduce an inconsistency with raw string literal syntax, as `#/.../#` on its own would not treat backslashes as literal, unlike `#"..."#`. If raw regex syntax were added, they would likely start at `##/.../##`. With raw strings, escape sequences must use the same number of `#`s as the delimiter, e.g `#"\#n"#` for a newline. However for raw regex literals it would be one fewer `#` than the delimiter e.g `##/\#n/##`. +However, introducing this as non-raw regex literal syntax would introduce an inconsistency with raw string literal syntax, as `#/.../#` on its own would not treat backslashes as literal, unlike `#"..."#`. If raw regex syntax was added, it would likely start at `##/.../##`. With raw strings, escape sequences must use the same number of `#`s as the delimiter, e.g `#"\#n"#` for a newline. However for raw regex literals it would be one fewer `#` than the delimiter e.g `##/\#n/##`. **TODO: What backslash rules do we want?** @@ -251,7 +253,14 @@ However we decided against this because: ### No custom literal -Instead of adding a custom regex literal, we could require users to explicitly write `Regex(compiling: "[abc]+")`. This would however lose all the benefits of parsing the literal at compile time, meaning that parse errors will instead be diagnosed at runtime, and no source tooling support (e.g syntax highlighting, refactoring actions) would be available. +Instead of adding a custom regex literal, we could require users to explicitly write `try! Regex(compiling: "[abc]+")`. This would be similar to `NSRegularExpression`, and loses all the benefits of parsing the literal at compile time. This would mean: + +- No source tooling support (e.g syntax highlighting, refactoring actions) would be available. +- Parse errors would be diagnosed at run time rather than at compile time. +- We would lose the type safety of typed captures. +- More verbose syntax is required. + +We therefore feel this would be a much less compelling feature without first class literal support. [SE-0168]: https://github.com/apple/swift-evolution/blob/main/proposals/0168-multi-line-string-literals.md [SE-0200]: https://github.com/apple/swift-evolution/blob/main/proposals/0200-raw-string-escaping.md From 4bb25b3f60aa16d19ec1b193d1eeb9992d5e880e Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 28 Mar 2022 13:31:16 +0100 Subject: [PATCH 020/133] Update to also pitch `#/.../#` --- Documentation/Evolution/DelimiterSyntax.md | 80 ++++++++++++++-------- 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 4afd3af96..237be3b1f 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -17,7 +17,7 @@ This proposal helps complete the story told in [Regex Type and Overview][regex-t ## Proposed solution -A regex literal will be introduced using `/.../` delimiters, within which the compiler will parse a regex (the details of which are outlined in [the Regex Syntax pitch][internal-syntax]): +A regex literal will be introduced in Swift 5.7 mode using `/.../` delimiters, within which the compiler will parse a regex (the details of which are outlined in [the Regex Syntax pitch][internal-syntax]): ```swift // Matches " = ", extracting the identifier and hex number @@ -28,11 +28,42 @@ The above regex literal will be inferred to be [the regex type][regex-type] `Reg Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternatives). Their ubiquity and familiarity makes them a compelling choice for Swift. -Due to the existing use of `/` in comment syntax and operators, there are some syntactic ambiguities to consider. While there are quite a few cases to consider, we do not feel that the impact of any individual case is sufficient to disqualify the syntax. Some of these ambiguities require a couple of source breaking language changes, and as such the `/.../` syntax will require upgrading to a new language mode in order to use. +Due to the existing use of `/` in comment syntax and operators, there are some syntactic ambiguities to consider. While there are quite a few cases to consider, we do not feel that the impact of any individual case is sufficient to disqualify the syntax. Some of these ambiguities require a couple of source breaking language changes, and as such the `/.../` syntax requires upgrading to a new language mode in order to use. + +A regex literal may also be spelled using an extended syntax `#/.../#`, which allows the placement of an arbitrary number of balanced `#` characters around a regex literal. This syntax allows regex literals to contain unescaped forward slashes, and provides a delimiter option which does not require a new language mode to use. ## Detailed design -Choosing `/` as the regex literal delimiter requires a number of ambiguities to be resolved. It also requires a couple of source breaking language changes to be introduced in a new language mode. +### Extended delimiters `#/.../#`, `##/.../##` + +A regex literal may be surrounded by an arbitrary number of balanced pound characters. This is a similar to raw string literal syntax introduced by [SE-0200], and allows a regex literal to use forward slashes without the need to escape them, e.g: + +```swift +let regex = #//usr/lib/modules/([^/]+)/vmlinuz/# +``` + +Additionally, this syntax provides a way to write a regex literal without needing to upgrade to Swift 5.7 mode. + +#### Escaping of backslashes + +This syntax differs from raw string literals `#"..."#` in that it does not treat backslashes as literal within the regex. A string literal `#"\n"#` represents the literal characters `\n`. However a regex literal `#/\n/#` remains a newline escape sequence. + +One of the primary motivations behind this escaping behavior in raw string literals is that it allows the contents to be easily transportable to/from e.g external files where escaping is unnecessary. For string literals, this suggests that backslashes be treated as literal by default. For regex literals, it instead suggests that backslashes should retain their semantic meaning, as it enables interoperability with regexes taken from outside your code without having to adjust escape sequences to match the delimiters used. + +With string literals, escaping can be tricky without the use of raw syntax, as backslashes may have semantic meaning to the consumer, rather than the compiler. For example: + +```swift +// Matches '\' * '=' * + +let regex = try NSRegularExpression(pattern: "\\\\w\\s*=\\s*\\d+", options: []) +``` + +In this case, the intent is not for the compiler to recognize any of these sequences as string literal escapes, it is instead for `NSRegularExpression` to interpret them as regex escape sequences. However this is not an issue for regex literals, as the regex parser is the only possible consumer of such escape sequences. Such a regex would instead be spelled as: + +```swift +let regex = /\\\w\s*=\s*\d+/ +``` + +Backslashes still require escaping to be treated as literal, however we don't expect this to be as common of an occurrence as needing to write a regex escape sequence such as `\s`, `\w`, or `\p{...}`, within a regex literal with extended delimiters `#/.../#`. ### Ambiguities with comment syntax @@ -55,11 +86,11 @@ Perhaps the most obvious parsing ambiguity with `/.../` delimiters is with comme ### Ambiguity with infix operators -There would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required `x + /y/` for regex literal interpretation. +There would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required `x + /y/` for regex literal interpretation. Alternatively, extended syntax may be used, e.g `x+#/y/#`. ### Regex syntax limitations -In order to help avoid further parsing ambiguities, a regex literal will not be parsed if it starts with a space, tab, or `)` character. Though the latter is already invalid regex syntax. +In order to help avoid further parsing ambiguities, a `/.../` regex literal will not be parsed if it starts with a space, tab, or `)` character. Though the latter is already invalid regex syntax. This restriction may be avoided by using extended `#/.../#` syntax. #### Rationale @@ -75,7 +106,7 @@ Builder { This is parsed as a single operator chain, however it is likely the user is expecting a regex literal. To resolve this ambiguity, a regex literal may not start with a space or tab character. The above therefore remains an operator chain. This takes advantage of the fact that infix operators require consistent spacing on either side. -If a space or tab is needed as the first character, it must be escaped, e.g: +If a space or tab is needed as the first character, it must be either escaped, e.g: ```swift Builder { @@ -85,6 +116,16 @@ Builder { } ``` +or extended syntax must be used, e.g: + +```swift +Builder { + 1 + #/ 2 /# + 3 +} +``` + The second ambiguity arises with Swift's ability to pass an unapplied operator reference as an argument to a function or subscript, for example: ```swift @@ -98,7 +139,7 @@ It should be noted that this only mitigates the issue, as it does not handle the ### Language changes required -In addition to ambiguities listed above, there are also some parsing ambiguities that would require the following language changes in Swift 6 mode: +In addition to ambiguities listed above, there are also some parsing ambiguities that would require the following language changes in Swift 5.7 mode: - Deprecation of prefix operators containing the `/` character. - Parsing `/,` and `/]` as the start of a regex literal if a closing `/` is found, rather than an unapplied operator in an argument list. For example, `fn(/, /)` becomes a regex literal rather than 2 unapplied operator arguments. @@ -124,6 +165,8 @@ Postfix `/` operators do not require banning, as they'd only be treated as regex #### `/,` and `/]` as regex literal openings +**TODO: Do we still want to break source here given we're also proposing `#/.../#`?** + As stated previously, there is a parsing ambiguity with unapplied operators in argument lists, tuples, and parentheses. Some of these cases can be mitigated by not parsing a regex literal if the starting character is `)`. However it does not solve the issue when the next character is `,` or `]`. Both of these are valid regex starting characters, and comma in particular may be a fairly common case for a regex. For example: @@ -163,15 +206,8 @@ This takes advantage of the fact that a regex literal will not be parsed if the
- ## Future Directions -### Raw literals - -The obvious choice here would follow string literals and use `#/.../#`. - -**TODO: What backslash rules do we want?** - ### Multi-line literals The obvious choice for a multi-line regex literal would be to use `///` delimiters, in accordance with the precedent set by multi-line string literals `"""`. But this signifies a (documentation) comment, so a different multi-line delimiter would be needed, with no obvious choice. However, it's not clear that we need multi-line regex literals. The existing literals can be used inside a regex builder DSL. @@ -184,16 +220,6 @@ Allowing non-semantic whitespace and other features of the extended syntax would Given the fact that `/` is an existing term of art for regular expressions, we feel it should be the preferred delimiter syntax. While it has some syntactic ambiguities, we do not feel that they are sufficient to disqualify the syntax. To evaluate this trade-off, below is a list of alternative delimiters that would not have the same ambiguities. -### Pound slash `#/.../#` - -This is a less syntactically ambiguous version of `/.../` that retains some of the term-of-art familiarity. It could potentially provide a natural path through which to introduce `/.../` in a new language mode, as users could drop the `#` characters once they upgrade. - -However, introducing this as non-raw regex literal syntax would introduce an inconsistency with raw string literal syntax, as `#/.../#` on its own would not treat backslashes as literal, unlike `#"..."#`. If raw regex syntax was added, it would likely start at `##/.../##`. With raw strings, escape sequences must use the same number of `#`s as the delimiter, e.g `#"\#n"#` for a newline. However for raw regex literals it would be one fewer `#` than the delimiter e.g `##/\#n/##`. - -**TODO: What backslash rules do we want?** - -It should also be noted that this option has the same block comment issue as `/.../` where e.g `#/[0-9]*/#` nested inside a block comment would prematurely end. Similarly, it's not clear how a multi-line version of the literal would be spelled. - ### Prefixed quote `re'...'` We could choose to use `re'...'` delimiters, for example: @@ -203,13 +229,13 @@ We could choose to use `re'...'` delimiters, for example: let regex = re'([[:alpha:]]\w*) = ([0-9A-F]+)' ``` -The use of two letter prefix could potentially be used as a namespace for future literal types. It would also have obvious extensions to raw and multi-line literals using `re#'...'#` and `re'''...'''` respectively. However, it is unusual for a Swift literal to be prefixed in this way. We also feel that its similarity to a string literal might have users confuse it with a raw string literal. +The use of two letter prefix could potentially be used as a namespace for future literal types. It would also have obvious extensions to extended and multi-line literals using `re#'...'#` and `re'''...'''` respectively. However, it is unusual for a Swift literal to be prefixed in this way. We also feel that its similarity to a string literal might have users confuse it with a raw string literal. -Also, there are a few items of regex grammar that use the single quote character as a metacharacter. These include named group definitions and references such as `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, as well as callout syntax `(?C'arg')`. The use of a single quote conflicts with the `re'...'` delimiter as it will be considered the end of the literal. However, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`, and `(?C"arg")`. Those could be required instead. A raw regex literal syntax e.g `re#'...'#` would also avoid this issue. +Also, there are a few items of regex grammar that use the single quote character as a metacharacter. These include named group definitions and references such as `(?'name')`, `(?('name'))`, `\g'name'`, `\k'name'`, as well as callout syntax `(?C'arg')`. The use of a single quote conflicts with the `re'...'` delimiter as it will be considered the end of the literal. However, alternative syntax exists for all of these constructs, e.g `(?)`, `\k`, and `(?C"arg")`. Those could be required instead. An extended regex literal syntax e.g `re#'...'#` would also avoid this issue. ### Prefixed double quote `re"...."` -This would be a double quoted version of `re'...'`, more similar to string literal syntax. This has the advantage that single quote regex syntax e.g `(?'name')` would continue to work without requiring the use of the alternative syntax or raw literal syntax. However it could be argued that regex literals are distinct from string literals in that they introduce their own specific language to parse. As such, regex literals are more like "program literals" than "data literals", and the use of single quote instead of double quote may be useful in expressing this difference. +This would be a double quoted version of `re'...'`, more similar to string literal syntax. This has the advantage that single quote regex syntax e.g `(?'name')` would continue to work without requiring the use of the alternative syntax or extended literal syntax. However it could be argued that regex literals are distinct from string literals in that they introduce their own specific language to parse. As such, regex literals are more like "program literals" than "data literals", and the use of single quote instead of double quote may be useful in expressing this difference. ### Single letter prefixed quote `r'...'` From 35d9132089d60596d558e4fac381c11d5b1c57f8 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 28 Mar 2022 21:18:21 +0100 Subject: [PATCH 021/133] Add DSL example --- Documentation/Evolution/DelimiterSyntax.md | 49 +++++++++++++++------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 237be3b1f..e421e7960 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -14,6 +14,21 @@ let re = /[0-9]+/ This proposal helps complete the story told in [Regex Type and Overview][regex-type] and [elsewhere][pitch-status]. Literals are compiled directly, allowing errors to be found at compile time, rather than at run time. Using a literal also allows editors to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see [Regex builder DSL][regex-dsl]). It would be difficult to support all of this if regexes could only be defined inside a string. +A regex literal also allows for seamless composition with the Regex DSL, enabling the intermixing of a regex syntax with other elements of the builder: + +```swift +// A regex literal for parsing an amount of currency in dollars or pounds. +let regex = Regex { + /([$£])/ + TryCapture { + OneOrMore(.digit) + "." + Repeat(.digit, count: 2) + } transform: { Amount(twoDecimalPlaces: $0) } +} +``` + +This flexibility allows for terse matching syntax to be used when it's suitable, and more explicit syntax where clarity and strong types are required. ## Proposed solution @@ -94,35 +109,41 @@ In order to help avoid further parsing ambiguities, a `/.../` regex literal will #### Rationale -This is due to 2 main ambiguities. The first of which arises when a `/.../` regex literal starts a new line. This is particularly problematic for result builders, where we expect it to be frequently used, for example: +This is due to 2 main parsing ambiguities. The first of which arises when a `/.../` regex literal starts a new line. This is particularly problematic for result builders, where we expect it to be frequently used, in particular within a `Regex` builder: ```swift -Builder { - 1 - / 2 / - 3 +let digit = Regex { + TryCapture(OneOrMore(.digit)) { Int($0) } +} +// Matches against + (' + ' | ' - ') + +let regex = Regex { + digit + / [+-] / + digit } ``` -This is parsed as a single operator chain, however it is likely the user is expecting a regex literal. To resolve this ambiguity, a regex literal may not start with a space or tab character. The above therefore remains an operator chain. This takes advantage of the fact that infix operators require consistent spacing on either side. +Instead of being parsed as 3 result builder elements, the second of which being a regex literal, this is instead parsed as a single operator chain with the operands `digit`, `[+-]`, and `digit`. This will therefore be diagnosed as semantically invalid. + +To avoid this issue, a regex literal may not start with a space or tab character. This takes advantage of the fact that infix operators require consistent spacing on either side. If a space or tab is needed as the first character, it must be either escaped, e.g: ```swift -Builder { - 1 - /\ 2 / - 3 +let regex = Regex { + digit + /\ [+-] / + digit } ``` or extended syntax must be used, e.g: ```swift -Builder { - 1 - #/ 2 /# - 3 +let regex = Regex { + digit + #/ [+-] /# + digit } ``` From f99dadb2b42bf5e859e8b944105216cc061597de Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 29 Mar 2022 12:32:05 +0100 Subject: [PATCH 022/133] Rejig motivation/solution --- Documentation/Evolution/DelimiterSyntax.md | 53 ++++++++++++++++------ 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index e421e7960..03046a7c3 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -4,7 +4,7 @@ ## Introduction -This proposal introduces regex literals to Swift source code. The proposed syntax mirrors literals in other programing languages such as Perl, JavaScript and Ruby. As in those languages, literals are delimited with the `/` character: +This proposal helps complete the story told in [Regex Type and Overview][regex-type] and [elsewhere][pitch-status]. We propose the introduction of regex literals to Swift source code. The proposed syntax mirrors literals in other programing languages such as Perl, JavaScript and Ruby. As in those languages, literals are delimited with the `/` character: ```swift let re = /[0-9]+/ @@ -12,9 +12,38 @@ let re = /[0-9]+/ ## Motivation -This proposal helps complete the story told in [Regex Type and Overview][regex-type] and [elsewhere][pitch-status]. Literals are compiled directly, allowing errors to be found at compile time, rather than at run time. Using a literal also allows editors to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see [Regex builder DSL][regex-dsl]). It would be difficult to support all of this if regexes could only be defined inside a string. +In [Regex Type and Overview][regex-type] we introduced the `Regex` type, which is able to dynamically compile a regex pattern: -A regex literal also allows for seamless composition with the Regex DSL, enabling the intermixing of a regex syntax with other elements of the builder: +```swift +let pattern = #"(\w+)\s\s+(\S+)\s\s+((?:(?!\s\s).)*)\s\s+(.*)"# +let regex = try! Regex(compiling: pattern) +// regex: Regex +``` + +The ability to compile regex patterns at runtime is useful for cases where it is e.g provided as user input, however it is suboptimal when the pattern is statically known for a number of reasons: + +- Regex syntax errors aren't detected until runtime, and explicit error handling (e.g `try!`) is required to deal with these errors. +- No special source tooling support, such as syntactic highlighting, code completion, and refactoring support, is available. +- Capture types aren't known until runtime, and as such a dynamic `AnyRegexOutput` capture type must be used. +- The syntax is overly verbose, especially for e.g an argument to a matching function. + +## Proposed solution + +We propose introducing a new kind of literal for a regex. In Swift 5.7 mode, a regex literal may be written using `/.../` delimiters: + +```swift +// Matches " = ", extracting the identifier and hex number +let regex = /(?[[:alpha:]]\w*) = (?[0-9A-F]+)/ +// regex: Regex<(Substring, identifier: Substring, hex: Substring)> +``` + +Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternatives). Their ubiquity and familiarity makes them a compelling choice for Swift. + +A regex literal may also be spelled using an extended syntax `#/.../#`, which allows the placement of an arbitrary number of balanced `#` characters around a regex literal. This syntax allows regex literals to contain unescaped forward slashes, and may be used without needing to upgrade to Swift 5.7 mode. + +Within a regex literal, the compiler will parse the regex syntax outlined in in [the Regex Syntax pitch][internal-syntax], and diagnose any errors at compile time. The capture types are automatically inferred based on the capture groups present in the regex. Using a literal allows editors to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see [Regex builder DSL][regex-dsl]). + +A regex literal also allows for seamless composition with the Regex DSL, enabling lightweight intermixing of a regex syntax with other elements of the builder: ```swift // A regex literal for parsing an amount of currency in dollars or pounds. @@ -30,24 +59,18 @@ let regex = Regex { This flexibility allows for terse matching syntax to be used when it's suitable, and more explicit syntax where clarity and strong types are required. -## Proposed solution - -A regex literal will be introduced in Swift 5.7 mode using `/.../` delimiters, within which the compiler will parse a regex (the details of which are outlined in [the Regex Syntax pitch][internal-syntax]): +Due to the existing use of `/` in comment syntax and operators, there are some syntactic ambiguities to consider. While there are quite a few cases to consider, we do not feel that the impact of any individual case is sufficient to disqualify the syntax. Some of these ambiguities require a couple of source breaking language changes, and as such the `/.../` syntax requires upgrading to a new language mode in order to use. -```swift -// Matches " = ", extracting the identifier and hex number -let regex = /([[:alpha:]]\w*) = ([0-9A-F]+)/ -``` +## Detailed design -The above regex literal will be inferred to be [the regex type][regex-type] `Regex<(Substring, Substring, Substring)>`, where the capture types have been automatically inferred. Errors in the regex will be diagnosed by the compiler. +### Named typed captures -Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternatives). Their ubiquity and familiarity makes them a compelling choice for Swift. +Regex literals have their capture types statically determined by the capture groups present. Each capture group adds an additional capture to the match tuple, with named capture groups receiving a corresponding tuple label. -Due to the existing use of `/` in comment syntax and operators, there are some syntactic ambiguities to consider. While there are quite a few cases to consider, we do not feel that the impact of any individual case is sufficient to disqualify the syntax. Some of these ambiguities require a couple of source breaking language changes, and as such the `/.../` syntax requires upgrading to a new language mode in order to use. +**TODO: Example** -A regex literal may also be spelled using an extended syntax `#/.../#`, which allows the placement of an arbitrary number of balanced `#` characters around a regex literal. This syntax allows regex literals to contain unescaped forward slashes, and provides a delimiter option which does not require a new language mode to use. -## Detailed design +**TODO: Should we cover more general typed capture behavior here? e.g Quantifier types. It overlaps with the typed capture behavior of the DSL tho** ### Extended delimiters `#/.../#`, `##/.../##` From eed1b24d482edb9110edce1b3f3839ffadbbe50e Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 29 Mar 2022 13:35:34 +0100 Subject: [PATCH 023/133] Expand on typed captures --- Documentation/Evolution/DelimiterSyntax.md | 26 +++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 03046a7c3..e34aba37a 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -41,7 +41,7 @@ Forward slashes are a regex term of art, and are used as the delimiters for rege A regex literal may also be spelled using an extended syntax `#/.../#`, which allows the placement of an arbitrary number of balanced `#` characters around a regex literal. This syntax allows regex literals to contain unescaped forward slashes, and may be used without needing to upgrade to Swift 5.7 mode. -Within a regex literal, the compiler will parse the regex syntax outlined in in [the Regex Syntax pitch][internal-syntax], and diagnose any errors at compile time. The capture types are automatically inferred based on the capture groups present in the regex. Using a literal allows editors to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see [Regex builder DSL][regex-dsl]). +Within a regex literal, the compiler will parse the regex syntax outlined in in [the Regex Syntax pitch][internal-syntax], and diagnose any errors at compile time. The capture types and labels are automatically inferred based on the capture groups present in the regex. Using a literal allows editors to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see [Regex builder DSL][regex-dsl]). A regex literal also allows for seamless composition with the Regex DSL, enabling lightweight intermixing of a regex syntax with other elements of the builder: @@ -63,21 +63,34 @@ Due to the existing use of `/` in comment syntax and operators, there are some s ## Detailed design -### Named typed captures +### Typed captures -Regex literals have their capture types statically determined by the capture groups present. Each capture group adds an additional capture to the match tuple, with named capture groups receiving a corresponding tuple label. +Regex literals have their capture types statically determined by the capture groups present. A initial `Substring` is always present for the entire match, and each capture group adds an additional capture to the match tuple, with named capture groups receiving a corresponding tuple label. Once matched, such captures may later be referenced: -**TODO: Example** +```swift +func matchHexAssignment(_ input: String) -> (String, Int)? { + let regex = /(?[[:alpha:]]\w*) = (?[0-9A-F]+)/ + // regex: Regex<(Substring, identifier: Substring, hex: Substring)> + + guard let match = regex.matchWhole(input), + let hex = Int(match.hex, radix: 16) + else { return nil } + + return (match.identifier, hex) +} +``` +Unnamed capture groups produce unlabeled tuple elements and must be referenced by their position, e.g `match.1`, `match.2`. -**TODO: Should we cover more general typed capture behavior here? e.g Quantifier types. It overlaps with the typed capture behavior of the DSL tho** +**TODO: Should we cover more general typed capture behavior from [StronglyTypedCaptures.md](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/StronglyTypedCaptures.md) here? There is some overlap with the typed capture behavior of the DSL tho, labels are the main thing that are literal specific** ### Extended delimiters `#/.../#`, `##/.../##` A regex literal may be surrounded by an arbitrary number of balanced pound characters. This is a similar to raw string literal syntax introduced by [SE-0200], and allows a regex literal to use forward slashes without the need to escape them, e.g: ```swift -let regex = #//usr/lib/modules/([^/]+)/vmlinuz/# +let regex = #/usr/lib/modules/([^/]+)/vmlinuz/# +// regex: Regex<(Substring, Substring)> ``` Additionally, this syntax provides a way to write a regex literal without needing to upgrade to Swift 5.7 mode. @@ -99,6 +112,7 @@ In this case, the intent is not for the compiler to recognize any of these seque ```swift let regex = /\\\w\s*=\s*\d+/ +// regex: Regex ``` Backslashes still require escaping to be treated as literal, however we don't expect this to be as common of an occurrence as needing to write a regex escape sequence such as `\s`, `\w`, or `\p{...}`, within a regex literal with extended delimiters `#/.../#`. From 7ad403791325b3dde44abc275e73026080e734dc Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 29 Mar 2022 20:31:49 +0100 Subject: [PATCH 024/133] Generalize language mode --- Documentation/Evolution/DelimiterSyntax.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index e34aba37a..8e50dec93 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -29,7 +29,7 @@ The ability to compile regex patterns at runtime is useful for cases where it is ## Proposed solution -We propose introducing a new kind of literal for a regex. In Swift 5.7 mode, a regex literal may be written using `/.../` delimiters: +We propose introducing a new kind of literal for a regex. In a new language mode, a regex literal may be written using `/.../` delimiters: ```swift // Matches " = ", extracting the identifier and hex number @@ -39,7 +39,7 @@ let regex = /(?[[:alpha:]]\w*) = (?[0-9A-F]+)/ Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternatives). Their ubiquity and familiarity makes them a compelling choice for Swift. -A regex literal may also be spelled using an extended syntax `#/.../#`, which allows the placement of an arbitrary number of balanced `#` characters around a regex literal. This syntax allows regex literals to contain unescaped forward slashes, and may be used without needing to upgrade to Swift 5.7 mode. +A regex literal may also be spelled using an extended syntax `#/.../#`, which allows the placement of an arbitrary number of balanced `#` characters around a regex literal. This syntax allows regex literals to contain unescaped forward slashes, and may be used without needing to upgrade to a new language mode. Within a regex literal, the compiler will parse the regex syntax outlined in in [the Regex Syntax pitch][internal-syntax], and diagnose any errors at compile time. The capture types and labels are automatically inferred based on the capture groups present in the regex. Using a literal allows editors to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see [Regex builder DSL][regex-dsl]). @@ -93,13 +93,13 @@ let regex = #/usr/lib/modules/([^/]+)/vmlinuz/# // regex: Regex<(Substring, Substring)> ``` -Additionally, this syntax provides a way to write a regex literal without needing to upgrade to Swift 5.7 mode. +Additionally, this syntax provides a way to write a regex literal without needing to upgrade to a new language mode. #### Escaping of backslashes This syntax differs from raw string literals `#"..."#` in that it does not treat backslashes as literal within the regex. A string literal `#"\n"#` represents the literal characters `\n`. However a regex literal `#/\n/#` remains a newline escape sequence. -One of the primary motivations behind this escaping behavior in raw string literals is that it allows the contents to be easily transportable to/from e.g external files where escaping is unnecessary. For string literals, this suggests that backslashes be treated as literal by default. For regex literals, it instead suggests that backslashes should retain their semantic meaning, as it enables interoperability with regexes taken from outside your code without having to adjust escape sequences to match the delimiters used. +One of the primary motivations behind this escaping behavior in raw string literals is that it allows the contents to be easily transportable to/from e.g external files where escaping is unnecessary. For string literals, this suggests that backslashes be treated as literal by default. For regex literals however, it instead suggests that backslashes should retain their semantic meaning, as it enables interoperability with regexes taken from outside your code without having to adjust escape sequences to match the delimiters used. With string literals, escaping can be tricky without the use of raw syntax, as backslashes may have semantic meaning to the consumer, rather than the compiler. For example: @@ -197,7 +197,7 @@ It should be noted that this only mitigates the issue, as it does not handle the ### Language changes required -In addition to ambiguities listed above, there are also some parsing ambiguities that would require the following language changes in Swift 5.7 mode: +In addition to ambiguities listed above, there are also some parsing ambiguities that would require the following language changes in a new language mode: - Deprecation of prefix operators containing the `/` character. - Parsing `/,` and `/]` as the start of a regex literal if a closing `/` is found, rather than an unapplied operator in an argument list. For example, `fn(/, /)` becomes a regex literal rather than 2 unapplied operator arguments. From f4ef0c2cf0c113e95d281c4a16220e52b03eb2fc Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 31 Mar 2022 13:03:53 +0100 Subject: [PATCH 025/133] Add multi-line mode --- Documentation/Evolution/DelimiterSyntax.md | 43 +++++++++++++++------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 8e50dec93..e06789a57 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -20,11 +20,11 @@ let regex = try! Regex(compiling: pattern) // regex: Regex ``` -The ability to compile regex patterns at runtime is useful for cases where it is e.g provided as user input, however it is suboptimal when the pattern is statically known for a number of reasons: +The ability to compile regex patterns at run time is useful for cases where it is e.g provided as user input, however it is suboptimal when the pattern is statically known for a number of reasons: -- Regex syntax errors aren't detected until runtime, and explicit error handling (e.g `try!`) is required to deal with these errors. +- Regex syntax errors aren't detected until run time, and explicit error handling (e.g `try!`) is required to deal with these errors. - No special source tooling support, such as syntactic highlighting, code completion, and refactoring support, is available. -- Capture types aren't known until runtime, and as such a dynamic `AnyRegexOutput` capture type must be used. +- Capture types aren't known until run time, and as such a dynamic `AnyRegexOutput` capture type must be used. - The syntax is overly verbose, especially for e.g an argument to a matching function. ## Proposed solution @@ -39,7 +39,7 @@ let regex = /(?[[:alpha:]]\w*) = (?[0-9A-F]+)/ Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternatives). Their ubiquity and familiarity makes them a compelling choice for Swift. -A regex literal may also be spelled using an extended syntax `#/.../#`, which allows the placement of an arbitrary number of balanced `#` characters around a regex literal. This syntax allows regex literals to contain unescaped forward slashes, and may be used without needing to upgrade to a new language mode. +A regex literal may also be spelled using an extended syntax `#/.../#`, which allows the placement of an arbitrary number of balanced `#` characters around a regex literal. This syntax allows regex literals to contain unescaped forward slashes, and may be used without needing to upgrade to a new language mode. This syntax further allows a multi-line mode when the opening delimiter is followed by a new line. Within a regex literal, the compiler will parse the regex syntax outlined in in [the Regex Syntax pitch][internal-syntax], and diagnose any errors at compile time. The capture types and labels are automatically inferred based on the capture groups present in the regex. Using a literal allows editors to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see [Regex builder DSL][regex-dsl]). @@ -86,7 +86,7 @@ Unnamed capture groups produce unlabeled tuple elements and must be referenced b ### Extended delimiters `#/.../#`, `##/.../##` -A regex literal may be surrounded by an arbitrary number of balanced pound characters. This is a similar to raw string literal syntax introduced by [SE-0200], and allows a regex literal to use forward slashes without the need to escape them, e.g: +A regex literal may be surrounded by an arbitrary number of balanced pound characters. This is a somewhat similar to the raw string literal syntax introduced by [SE-0200], and allows a regex literal to use forward slashes without the need to escape them, e.g: ```swift let regex = #/usr/lib/modules/([^/]+)/vmlinuz/# @@ -99,7 +99,7 @@ Additionally, this syntax provides a way to write a regex literal without needin This syntax differs from raw string literals `#"..."#` in that it does not treat backslashes as literal within the regex. A string literal `#"\n"#` represents the literal characters `\n`. However a regex literal `#/\n/#` remains a newline escape sequence. -One of the primary motivations behind this escaping behavior in raw string literals is that it allows the contents to be easily transportable to/from e.g external files where escaping is unnecessary. For string literals, this suggests that backslashes be treated as literal by default. For regex literals however, it instead suggests that backslashes should retain their semantic meaning, as it enables interoperability with regexes taken from outside your code without having to adjust escape sequences to match the delimiters used. +One of the primary motivations behind this escaping behavior in raw string literals is that it allows the contents to be easily transportable to/from e.g external files where escaping is unnecessary. For string literals, this suggests that backslashes be treated as literal by default. For regex literals however, it instead suggests that backslashes should retain their semantic meaning. This enables interoperability with regexes taken from outside your code without having to adjust escape sequences to match the delimiters used. With string literals, escaping can be tricky without the use of raw syntax, as backslashes may have semantic meaning to the consumer, rather than the compiler. For example: @@ -117,6 +117,24 @@ let regex = /\\\w\s*=\s*\d+/ Backslashes still require escaping to be treated as literal, however we don't expect this to be as common of an occurrence as needing to write a regex escape sequence such as `\s`, `\w`, or `\p{...}`, within a regex literal with extended delimiters `#/.../#`. +#### Multi-line mode + +Extended regex delimiters additionally support a multi-line mode when the opening delimiter is followed by a new line. For example: + +```swift +let regex = #/ + # Match a line of the format e.g "DEBIT 03/03/2022 Totally Legit Shell Corp $2,000,000.00" + (? \w+) \s\s+ + (? \S+) \s\s+ + (? (?: (?!\s\s) . )+) \s\s+ # Note that account names may contain spaces. + (? .*) + /# +``` + +In this mode, [extended regex syntax][extended-regex-syntax] `(?x)` is enabled by default. This means that whitespace becomes non-semantic, and end-of-line comments are supported with `# comment` syntax. + +This mode is supported with any (non-zero) number of pound characters in the delimiter. Similar to multi-line strings introduced by [SE-0168], the closing delimiter must appear on a new line. To avoid parsing confusion, such a literal will not be parsed if a closing delimiter is not present. This avoids inadvertently treating the rest of the file as regex if you only type the opening. + ### Ambiguities with comment syntax Perhaps the most obvious parsing ambiguity with `/.../` delimiters is with comment syntax. @@ -266,13 +284,7 @@ This takes advantage of the fact that a regex literal will not be parsed if the ## Future Directions -### Multi-line literals - -The obvious choice for a multi-line regex literal would be to use `///` delimiters, in accordance with the precedent set by multi-line string literals `"""`. But this signifies a (documentation) comment, so a different multi-line delimiter would be needed, with no obvious choice. However, it's not clear that we need multi-line regex literals. The existing literals can be used inside a regex builder DSL. - -### Regex extended syntax - -Allowing non-semantic whitespace and other features of the extended syntax would be highly desired, with no obvious choice for a literal. Perhaps the need is also lessened by the ability to use regex literals inside the regex builder DSL. +**TODO: Do we have any other future directions now that extended multi-line syntax has been subsumed?** ## Alternatives Considered @@ -319,6 +331,10 @@ It should also be noted that `#regex(...)` would introduce a syntactic inconsist We could reduce the visual weight of `#regex(...)` by only requiring `#(...)`. However it would still retain the same issues, such as still looking potentially visually noisy as an argument, and having suboptimal behavior for parenthesis balancing. It is also not clear why regex literals would deserve such privileged syntax. +### Using a different delimiter for multi-line + +Instead of re-using the extended delimiter syntax `#/.../#` for multi-line regex literals, we could choose a different delimiter for it. Unfortunately, the obvious choice for a multi-line regex literal would be to use `///` delimiters, in accordance with the precedent set by multi-line string literals `"""`. This signifies a (documentation) comment, and as such would not be viable. + ### Reusing string literal syntax Instead of supporting a first-class literal kind for regex, we could instead allow users to write a regex in a string literal, and parse, diagnose, and generate the appropriate code when it's coerced to the `Regex` type. @@ -352,3 +368,4 @@ We therefore feel this would be a much less compelling feature without first cla [regex-type]: https://forums.swift.org/t/pitch-regex-type-and-overview/56029 [pitch-status]: https://github.com/apple/swift-experimental-string-processing/issues/107 [regex-dsl]: https://forums.swift.org/t/pitch-regex-builder-dsl/56007 +[extended-regex-syntax]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntax.md#extended-syntax-modes From b25a0b8e094b743193f2b6ed28815db0600ca0fc Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 31 Mar 2022 11:50:14 -0700 Subject: [PATCH 026/133] Remove Normalization and Grapheme data for SPI --- Sources/_CUnicode/Apple/NormalizationData.h | 1627 -------------- Sources/_CUnicode/Common/GraphemeData.h | 141 -- Sources/_CUnicode/Common/NormalizationData.h | 1985 ----------------- Sources/_CUnicode/UnicodeGrapheme.c | 72 - Sources/_CUnicode/UnicodeNormalization.c | 116 - Sources/_CUnicode/include/UnicodeData.h | 26 - Sources/_StringProcessing/Unicode/Data.swift | 188 -- .../_StringProcessing/Unicode/Graphemes.swift | 668 ------ .../Unicode/Normalization.swift | 406 ---- 9 files changed, 5229 deletions(-) delete mode 100644 Sources/_CUnicode/Apple/NormalizationData.h delete mode 100644 Sources/_CUnicode/Common/GraphemeData.h delete mode 100644 Sources/_CUnicode/Common/NormalizationData.h delete mode 100644 Sources/_CUnicode/UnicodeGrapheme.c delete mode 100644 Sources/_CUnicode/UnicodeNormalization.c delete mode 100644 Sources/_StringProcessing/Unicode/Data.swift delete mode 100644 Sources/_StringProcessing/Unicode/Graphemes.swift delete mode 100644 Sources/_StringProcessing/Unicode/Normalization.swift diff --git a/Sources/_CUnicode/Apple/NormalizationData.h b/Sources/_CUnicode/Apple/NormalizationData.h deleted file mode 100644 index cd1858f66..000000000 --- a/Sources/_CUnicode/Apple/NormalizationData.h +++ /dev/null @@ -1,1627 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -// This was auto-generated by utils/gen-unicode-data/GenNormalization, -// please do not edit this file yourself! - -#ifndef NORMALIZATION_DATA_H -#define NORMALIZATION_DATA_H - -#include "stdint.h" - -static const uint16_t _swift_stdlib_normData_data[66] = { - 0x4, 0x358, 0xA0, 0x50, 0x6C0, 0x44, 0x80, 0x48, 0x720, 0x3, 0x733, 0x88, 0xC8, 0x3C, 0xD0, 0xF0, - 0x3D0, 0x750, 0xB8, 0x8, 0x120, 0xA8, 0xD8, 0x70, 0x118, 0x108, 0x2DC, 0x408, 0x78, 0x338, 0x740, - 0x60, 0xF8, 0x98, 0xB0, 0x6F0, 0x38, 0x6E4, 0x6E0, 0x68, 0x6D0, 0x6B0, 0x650, 0xC, 0x58, 0xE8, - 0x420, 0x748, 0x6C4, 0x410, 0x4C, 0x100, 0xE0, 0x730, 0x710, 0x2A0, 0xC0, 0x784, 0x3B0, 0x110, - 0x30, 0x700, 0x90, 0x654, 0x734, 0x1, -}; - -static const uint8_t _swift_stdlib_normData_data_indices[3041] = { - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x40, 0x40, 0x40, 0x40, - 0x40, 0x35, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x35, 0x35, 0x40, 0x35, 0x40, 0x35, 0x40, - 0x40, 0x1E, 0x26, 0x26, 0x26, 0x26, 0x1E, 0x30, 0x26, 0x26, 0x26, 0x26, 0x26, 0x2A, 0x2A, 0x25, - 0x25, 0x25, 0x25, 0x3F, 0x3F, 0x26, 0x26, 0x26, 0x26, 0x25, 0x25, 0x26, 0x25, 0x25, 0x26, 0x26, - 0x13, 0x13, 0x13, 0x13, 0x2B, 0x26, 0x26, 0x26, 0x26, 0x35, 0x35, 0x35, 0xA, 0xA, 0x40, 0xA, 0xA, - 0x39, 0x35, 0x26, 0x26, 0x26, 0x35, 0x35, 0x35, 0x26, 0x26, 0x35, 0x35, 0x35, 0x26, 0x26, 0x26, - 0x26, 0x35, 0x1E, 0x26, 0x26, 0x35, 0x2F, 0x11, 0x11, 0x2F, 0x11, 0x11, 0x2F, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x9, 0x9, 0x41, 0x41, 0x9, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x35, 0x35, 0x35, 0x35, 0x35, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x26, 0x35, 0x35, 0x35, - 0x35, 0x26, 0x35, 0x35, 0x35, 0x23, 0x26, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x35, 0x35, 0x26, 0x35, 0x35, 0x23, 0x8, 0x35, 0x3, 0x2C, 0x1F, 0x27, 0x17, - 0x1C, 0x6, 0xB, 0x3E, 0x21, 0x21, 0x2, 0x15, 0x22, 0x12, 0x38, 0xC, 0x35, 0x26, 0x3E, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0xF, 0x20, 0x33, 0x41, 0x41, 0x41, 0x41, 0x41, 0x16, 0x34, - 0x2D, 0xF, 0x20, 0x33, 0x19, 0x3B, 0x40, 0x40, 0x25, 0x26, 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, - 0x35, 0x35, 0x26, 0x18, 0x41, 0x41, 0x41, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x26, 0x35, 0x35, 0x35, 0x26, 0x35, 0x35, 0x26, 0x14, 0x35, 0x26, 0x35, 0x35, 0x26, - 0x35, 0x35, 0x26, 0x26, 0x26, 0x35, 0x26, 0x26, 0x35, 0x26, 0x35, 0x35, 0x35, 0x26, 0x35, 0x26, - 0x35, 0x26, 0x35, 0x26, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x35, 0x26, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x26, 0x26, 0x35, 0x26, 0x26, 0x26, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x26, 0x26, 0x26, 0x26, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x35, 0x35, 0x26, 0x35, 0x35, 0x26, 0x35, - 0x35, 0x35, 0x26, 0x26, 0x26, 0x16, 0x34, 0x2D, 0x35, 0x35, 0x35, 0x26, 0x35, 0x35, 0x26, 0x26, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x41, 0x41, 0x41, 0xD, 0x7, 0x35, 0x26, 0x35, 0x35, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x24, 0x0, 0x41, 0x41, 0x7, 0x0, 0x9, 0x9, 0x9, 0x35, 0x9, 0x9, 0x24, - 0x7, 0x9, 0x9, 0x9, 0x9, 0x24, 0x7, 0x24, 0x0, 0x41, 0x41, 0x41, 0x7, 0x0, 0x0, 0x9, 0x9, 0x41, - 0x0, 0x41, 0x41, 0x41, 0x7, 0x0, 0x24, 0x41, 0x7, 0x37, 0x1A, 0x24, 0x41, 0x0, 0x41, 0x41, 0x41, - 0x41, 0x7, 0x0, 0x0, 0x7, 0x7, 0x0, 0x41, 0x41, 0x41, 0x7, 0x0, 0x32, 0x0, 0x41, 0x41, 0x41, 0x41, - 0x0, 0x1D, 0x1D, 0x7, 0x1, 0x1, 0x1, 0x1, 0x3A, 0x3A, 0x7, 0x10, 0x10, 0x10, 0x10, 0x26, 0x26, - 0x26, 0x26, 0x4, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x1B, 0x31, 0x9, 0x2E, 0x9, 0x9, 0x9, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x9, 0x35, 0x35, 0x7, 0x35, 0x35, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x26, 0x41, 0x0, - 0x24, 0x7, 0x7, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x35, 0x35, 0x35, 0x7, 0x7, - 0x7, 0x7, 0x35, 0x8, 0x23, 0x35, 0x26, 0x35, 0x26, 0x7, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x26, 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x35, 0x35, 0x26, - 0x26, 0x26, 0x35, 0x35, 0x26, 0x26, 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x35, 0x35, 0x35, 0x35, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x24, 0x0, 0x41, 0x41, 0x41, 0x41, 0x41, 0x7, 0x35, 0x26, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x7, 0x7, 0x24, 0x7, 0x7, 0x24, 0x35, 0x35, 0x35, 0x13, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x35, 0x35, 0x26, 0x26, 0x26, 0x26, 0x35, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x26, 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x26, 0x35, 0x35, 0x11, 0x29, 0x26, 0x2A, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x1E, 0x8, 0x8, - 0x26, 0x28, 0x35, 0x2F, 0x26, 0x35, 0x26, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x9, 0x41, 0x9, 0x41, 0x9, 0x41, 0x9, 0x41, 0x9, 0x41, 0x9, 0x41, 0x9, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x9, 0x41, 0x9, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x9, 0x41, 0x9, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x9, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x9, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x9, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x9, 0x41, - 0x41, 0x9, 0x9, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x9, 0x41, 0x9, 0x41, 0x9, 0x9, 0x9, 0x35, - 0x35, 0x13, 0x13, 0x35, 0x35, 0x35, 0x35, 0x13, 0x13, 0x13, 0x35, 0x35, 0x35, 0x13, 0x13, 0x35, - 0x26, 0x35, 0x13, 0x13, 0x26, 0x26, 0x26, 0x26, 0x35, 0x9, 0x9, 0x9, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x9, 0x9, 0x9, 0x35, 0x35, 0x35, 0x7, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x28, 0x8, 0x1E, - 0x23, 0x3D, 0x3D, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x5, 0x5, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x7, 0x7, 0x7, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x26, 0x26, 0x26, 0x7, 0x24, 0x7, 0x35, 0x35, 0x35, 0x26, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x7, 0x7, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0xE, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x35, 0x35, 0x26, 0x26, 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x35, 0x35, 0x13, 0x26, 0x7, - 0x35, 0x26, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x26, 0x35, 0x35, 0x35, 0x26, 0x35, 0x26, - 0x26, 0x26, 0x26, 0x35, 0x26, 0x35, 0x26, 0x7, 0x7, 0x7, 0x41, 0x41, 0x41, 0x7, 0xD, 0x35, 0x35, - 0x35, 0x0, 0x41, 0x41, 0x7, 0x7, 0x24, 0x7, 0x24, 0x7, 0x24, 0x24, 0x7, 0x24, 0x24, 0x0, 0x41, - 0x41, 0x7, 0x0, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x7, 0x24, - 0x35, 0x0, 0x0, 0x41, 0x41, 0x0, 0x41, 0x7, 0x24, 0x0, 0x41, 0x41, 0x7, 0x24, 0x7, 0x7, 0x24, 0x7, - 0x7, 0x24, 0x0, 0x41, 0x7, 0x7, 0x24, 0x7, 0x7, 0x7, 0x7, 0x7, 0x24, 0x7, 0x7, 0x7, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x3C, 0x3C, 0x13, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x4, 0x4, 0x13, 0x13, 0x13, 0x36, 0x4, 0x4, 0x4, 0x4, 0x4, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x26, 0x35, 0x35, 0x35, 0x35, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x24, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, - 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, -}; - -static const uint16_t _swift_stdlib_normData_ranks[402] = { - 0x0, 0x24, 0x24, 0x2A, 0x36, 0x42, 0x44, 0x47, 0x4B, 0x4B, 0x4B, 0x4B, 0x0, 0x0, 0x0, 0x0, 0x35, - 0x0, 0x31, 0x5C, 0x63, 0x9B, 0x0, 0xE, 0xE, 0xE, 0x2E, 0x0, 0x3F, 0x51, 0x59, 0x61, 0x0, 0x9, 0xE, - 0x30, 0x30, 0x0, 0x0, 0x33, 0x33, 0x48, 0x0, 0x1, 0xC, 0x18, 0x33, 0x0, 0x0, 0x5, 0x1F, 0x22, 0x0, - 0x8, 0x3D, 0x41, 0x4E, 0x0, 0x5, 0xA, 0xE, 0x12, 0x0, 0x2, 0x2, 0xC, 0xD, 0x0, 0x6, 0x6, 0xB, 0xB, - 0x0, 0x9, 0xC, 0x11, 0x11, 0x0, 0x5, 0xC, 0xC, 0x13, 0x0, 0x2, 0xA, 0x1F, 0x24, 0x0, 0x2, 0x5, - 0x6, 0x6, 0x0, 0x0, 0x15, 0x2D, 0x30, 0x0, 0x3, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, - 0x2, 0x2, 0x2, 0x0, 0x1, 0x1, 0x1, 0x4, 0x0, 0x0, 0x0, 0x2, 0xC, 0x0, 0x1E, 0x23, 0x2C, 0x35, 0x0, - 0x2, 0x5, 0x6, 0x6, 0x0, 0x18, 0x1B, 0x1B, 0x1B, 0x0, 0x40, 0x80, 0xC0, 0xFB, 0x0, 0x3A, 0x72, - 0xAC, 0xE7, 0x0, 0x1D, 0x1D, 0x1D, 0x2A, 0x0, 0x4, 0x4, 0x7, 0xA, 0x0, 0x5, 0x14, 0x1E, 0x26, 0x0, - 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x1, 0x1, 0x1, 0x0, 0x0, 0x3, 0x3, 0x4, 0x0, 0x10, 0x20, 0x20, 0x20, - 0x0, 0x0, 0x8, 0x1F, 0x32, 0x0, 0x6, 0x6, 0x6, 0x6, 0x0, 0x0, 0x0, 0xB, 0xD, 0x0, 0x2, 0x2, 0x2, - 0x2, 0x0, 0x1, 0x2, 0x2, 0x3, 0x0, 0x5, 0x6, 0x6, 0x8, 0x0, 0x0, 0x0, 0x8, 0xA, 0x0, 0x0, 0x0, - 0x0, 0x1, 0x0, 0x0, 0x20, 0x60, 0xA0, 0x0, 0x40, 0x74, 0xB2, 0xF2, 0x0, 0x1A, 0x30, 0x3D, 0x3D, - 0x0, 0x10, 0x10, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x5, 0x5, 0x5, - 0x5, 0x0, 0x0, 0x2, 0x6, 0x6, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, - 0x0, 0x2, 0x0, 0x0, 0xB, 0xF, 0xF, 0x0, 0x0, 0x3, 0x8, 0x8, 0x0, 0x5, 0x6, 0x8, 0x8, 0x0, 0x2, - 0x2, 0x2, 0x4, 0x0, 0xE, 0x13, 0x13, 0x13, 0x0, 0x3, 0x9, 0xB, 0xB, 0x0, 0x0, 0x5, 0x5, 0x6, 0x0, - 0x0, 0x2, 0x2, 0x3, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x4, 0x5, 0x0, 0x0, 0x1, 0x3, 0x3, - 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x3, 0x4, 0x0, 0x0, 0x0, 0x5, 0xC, 0x0, 0x0, 0x2, 0x2, - 0x2, 0x0, 0x0, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1F, 0x29, 0x29, 0x2C, 0x0, 0x0, 0x0, - 0x0, 0x26, 0x0, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x1, 0x5, 0x5, 0x0, 0x7, 0x7, 0xE, 0xE, 0x0, 0x0, - 0x30, 0x70, 0xB0, 0x0, 0x40, 0x80, 0xC0, 0x100, 0x0, 0x40, 0x4E, 0x4E, 0x4E, -}; - -static const uint64_t _swift_stdlib_normData[403] = { - 0xC, 0x6D03FFE5FFFF, 0x0, 0x3F0000000, 0xEC1C9C0000000000, 0x1BFF, 0x4200000, 0x60000400000000, - 0x1058, 0x0, 0x0, 0x0, 0x3800, 0x0, 0x0, 0x0, 0xBE7EFFBF3E7EFFBF, 0xFFFF, 0xF1F87EF1FF3FFFFC, - 0x7FFFFF3FFFF3, 0xE000000180030000, 0xFFFFFF31FFCFDFFF, 0x45CFFF, 0xFFFC0, 0x0, 0x0, - 0xFFFFFFFF00000000, 0xEEFFFF, 0xFFFFFFFF7FFFFFFF, 0xFC000001D7E04010, 0x187C000001, 0x200708B0000, - 0x12C0200, 0xC00000708B0000, 0xF8, 0x33FFCFCFCCF0006, 0x0, 0x18E0000, 0x0, 0xB6BFFFFFFFFFFE, 0x0, - 0xF8000000007C07FF, 0x1BEFFFF, 0x10000, 0x9FC8000500000000, 0x2000000003D9F, 0x7FFFFFF0000, - 0x2160000, 0x0, 0xF800000000000000, 0x3EEFFBC00000200F, 0xE0000000000, 0x2490000, 0xFF000000, - 0xFFFFFFFBFFFFFC00, 0x1012020000000000, 0xFF1E2000, 0x26B0000, 0x3800500000000000, 0x40000000B080, - 0x2000104800000000, 0x4E00, 0x2B90000, 0x200010000000, 0x0, 0x30C0390050000000, 0x10000000000000, - 0x2CB0000, 0x803C004000, 0x0, 0x6021001000, 0x0, 0x2D81000, 0x602D85, 0x5800000000000000, - 0x803C00, 0x0, 0x2E48400, 0xF400, 0xF00070000000000, 0x0, 0xF00070000000000, 0x2F70000, - 0x300000000000000, 0x1084200802A00000, 0x200800DF3D7E0200, 0x4002001084, 0x30A0000, - 0x4040000000000000, 0x680, 0x20000000, 0x0, 0x32E0000, 0x0, 0x3FFFFE00000000, 0xFFFFFF0000000000, - 0x7, 0x3340000, 0xE000000000000000, 0x0, 0x0, 0x0, 0x3640000, 0x0, 0x0, 0x0, 0x1000000030, - 0x3670000, 0x0, 0x2004000000000000, 0x0, 0x0, 0x36A0000, 0x200000000000000, 0x0, 0x0, 0xE00, - 0x36C0000, 0x0, 0x0, 0x1800000, 0x9FE0000100000000, 0x3700000, 0x7FFFBFFF00000000, - 0x5540000000000000, 0x1B283000000004, 0xFF8000000, 0x37C0000, 0xC00, 0xC0040, 0x800000, 0x0, - 0x3B10000, 0x21FDFFF700000000, 0x310, 0x0, 0x0, 0x3B70000, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFF0BFFFFFF, 0x3D2FFFF, 0xFFFF03FFFFFFFFFF, 0x3F3FFFFFFFFF3F3F, - 0xFFFF3FFFFFFFAAFF, 0xFFDE5FDFFFFFFFFF, 0x4DDEFCF, 0x33FDCFFFF, 0x0, 0x0, 0x1FFF000000000000, - 0x5D1FFE2, 0xC40000000000001, 0x0, 0x40000C0000000000, 0xE0000000, 0x6070000, 0x5000001210, - 0x333E00500000292, 0xF00000000333, 0x3C0F00000000, 0x6110000, 0x6000000, 0x0, 0x0, 0x0, 0x6370000, - 0x0, 0x10000000, 0x0, 0x0, 0x6390000, 0x0, 0x38000, 0x0, 0x80000000, 0x63A0000, - 0xFFFF000000000000, 0xFFFF, 0x0, 0x0, 0x63E0000, 0x0, 0x50000000FC000000, 0x36DB02A55555, - 0x2A5555550004610, 0x65E36DB, 0x47900000, 0x0, 0x0, 0x0, 0x69A0000, 0x0, 0x0, 0x3FF0800000000000, - 0xC0000000, 0x6A00000, 0x300000000, 0x0, 0x0, 0x0, 0x6AD0000, 0x4000000000, 0x1000, 0x0, - 0x1000000000, 0x6AFFFFF, 0x3800000000000003, 0x800000000, 0x0, 0x10008, 0x6C20000, 0x0, 0x0, - 0xC19D000000000000, 0x40000000000002, 0x6CA0000, 0x0, 0x0, 0x0, 0x20000000, 0x6D40000, 0x0, - 0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x6D5FFFF, 0xFFFFFFFFFFFFFFFF, - 0xFC657FE53FFFFFFF, 0x3FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x785FFFF, 0x3FFFFFF, - 0x5F7FFC00E0000000, 0x7FDB, 0x0, 0x8870000, 0xFFFF000000000000, 0x0, 0x0, 0x0, 0x8C40000, 0x0, - 0x0, 0x0, 0x20000000, 0x8D40000, 0x0, 0x0, 0x1000000000000, 0x0, 0x8D50000, 0x7C0000000000000, - 0x0, 0x0, 0x0, 0x8D60000, 0x0, 0xA00000000000, 0x87000000, 0x0, 0x8DB0000, 0x60000000000000, 0x0, - 0x0, 0x0, 0x8E10000, 0x0, 0xF00000, 0x0, 0x0, 0x8E30000, 0x0, 0x0, 0x0, 0x1800, 0x8E70000, 0x0, - 0x1FFC00000, 0x3C0000, 0x0, 0x8E90000, 0x0, 0x8001000000000040, 0x600080014000000, 0x0, 0x8F80007, - 0x18C0800000, 0x800000000, 0x401000000000000, 0x0, 0x9030000, 0x600000, 0x0, 0x0, 0x600, - 0x90B0000, 0x1FC0008038005800, 0x1F, 0x0, 0x0, 0x90F0000, 0x40000044, 0x7C01000000000000, 0xC, - 0x0, 0x9220000, 0x0, 0x18C0080000000, 0x0, 0x800000000000, 0x92D0000, 0x0, 0xC00000, 0x0, 0x800, - 0x9330000, 0x0, 0x0, 0x0, 0x600, 0x9360000, 0x0, 0x0, 0x6101000000000000, 0x8, 0x9380000, 0x0, - 0x10000, 0x80001000000000, 0x0, 0x93D0200, 0x0, 0x0, 0x8000, 0x0, 0x9410000, 0x0, 0x0, 0x34, - 0x800000, 0x9420000, 0x0, 0x0, 0x1F00000000, 0x7F00000000, 0x9460000, 0x0, 0x30000, 0x0, 0x0, - 0x9520000, 0x0, 0x4000000000000000, 0x0, 0x0, 0x9540000, 0x0, 0x0, 0x0, 0x0, 0x955C000, - 0xFE7F807E3FF, 0x1F8003C00, 0x0, 0x1C00000000, 0x9570000, 0x0, 0x0, 0x0, 0x7DBF9FFFF7F0000, - 0x9830000, 0x0, 0x0, 0x0, 0x7F000000000000, 0x9A90000, 0x0, 0x4000, 0xF000, 0x0, 0x9B00000, - 0x7F0000, 0x0, 0x7F0, 0x0, 0x9B50000, 0x0, 0xFFFFFFFFFFFF0000, 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, 0x9C3FFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, 0xA83FFFF, 0xFFFFFFFFFFFFFFFF, 0x3FFF, 0x0, 0x0, 0xB930000, -}; - -#define NFD_DECOMP_LEVEL_COUNT 11 - -static const uint16_t _swift_stdlib_nfd_decomp_sizes[11] = { - 0x80D, 0x4F8, 0x32E, 0x1EF, 0x137, 0xC3, 0x7B, 0x54, 0x40, 0x40, 0x40, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys0[33] = { - 0xA610E3C4A94D1E98, 0x4360A421841EF395, 0x4A0E48481C9E3B08, 0x8B20EA3110533240, - 0xC061C012EA208593, 0x95C804089E38538B, 0x17084374F3DF67A1, 0x5158D1B16C820914, - 0x3D2C95027217D407, 0xE0A8002869046382, 0xD2B2DA86D21400D, 0xE84418198616B103, 0x2C022C18A11A4589, - 0x18D0391017E61E1, 0x54192C84C6AE0E01, 0x6418A05096560544, 0x4C099C24942F500D, 0xCA734C8250149DED, - 0x8C6150D379A881C8, 0x1252A6506620EB68, 0xC00B1A258990DC9C, 0x48058A3583C1D8F4, 0x130FD1922DE0BA0, - 0xD1098D6244CFC060, 0xB8D48414124B032E, 0xA164FF04EBE4961B, 0x21DBF90ED081085, 0x9290B24898B8A16, - 0xD08E25DE422898A5, 0x9054380D01CFC262, 0x12209144B002A104, 0xE201C04A10504414, 0x519, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys1[20] = { - 0x8144CC4A0D2250A4, 0x8D7027B878E6AF00, 0xC8808058019A1327, 0x8440182CDA8A8000, - 0x11F2546640A88578, 0x809941041616F30A, 0x81EA43018F6211B3, 0xDF5248898CC52106, - 0x706040F034804ACA, 0xC466784A249C4D00, 0xD6A01234AE244BA2, 0x4E7E81014034B644, 0x4C4A90003B01AA1, - 0x505241F44B1C495A, 0xB1C12D3C10609621, 0x219508C06A2B8021, 0xD888C002DC100EA5, - 0xA5031DD40B961481, 0x3618E0842D48E703, 0x24462188051181, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys2[13] = { - 0x18688558A53CB60D, 0x4CF22409093204F, 0x33717C5A9D12141A, 0x276322F3444A8164, 0x81540E02747F08D0, - 0x8116C1618AA2A163, 0x109AAB2395D06B8, 0x8E7142BC806600BB, 0x387205C91105908, 0x1460C4392FAE5909, - 0x52DA004F130A8506, 0x6A886C8311090735, 0x24B8FCD40E21, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys3[8] = { - 0x60A631406899DC30, 0xB2A84020DD5240B1, 0x149D1EE14D820B49, 0xC8CAFB380940121, 0x300040A927914309, - 0x6B027CBCC7050271, 0x2623507C35B2408B, 0x832091C1B4, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys4[5] = { - 0x78605890CC980E05, 0x2C28AA1106247AAB, 0xB83855821C09229F, 0x1610C434CFB82648, 0xB2A8351190804, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys5[4] = { - 0x42B00C82848316E9, 0x481902D129498466, 0xF0126DE0FA042361, 0x1, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys6[2] = { - 0x800862A20C0592A5, 0xCA94800F00F862, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys7[2] = { - 0xA703754B0198000, 0x73104, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys8[1] = { - 0x2436652504A5F5CA, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys9[1] = { - 0x6198C101C6044C21, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys10[1] = { - 0x404228114000004, -}; - -static const uint64_t * const _swift_stdlib_nfd_decomp_keys[11] = { - _swift_stdlib_nfd_decomp_keys0, _swift_stdlib_nfd_decomp_keys1, _swift_stdlib_nfd_decomp_keys2, - _swift_stdlib_nfd_decomp_keys3, _swift_stdlib_nfd_decomp_keys4, _swift_stdlib_nfd_decomp_keys5, - _swift_stdlib_nfd_decomp_keys6, _swift_stdlib_nfd_decomp_keys7, _swift_stdlib_nfd_decomp_keys8, - _swift_stdlib_nfd_decomp_keys9, _swift_stdlib_nfd_decomp_keys10, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks0[5] = { - 0x0, 0xCC, 0x185, 0x253, 0x310, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks1[3] = { - 0x315, 0x3D0, 0x488, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks2[2] = { - 0x4DF, 0x5AB, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks3[1] = { - 0x61E, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks4[1] = { - 0x6D6, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks5[1] = { - 0x74A, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks6[1] = { - 0x792, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks7[1] = { - 0x7B9, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks8[1] = { - 0x7D4, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks9[1] = { - 0x7F0, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks10[1] = { - 0x804, -}; - -static const uint16_t * const _swift_stdlib_nfd_decomp_ranks[11] = { - _swift_stdlib_nfd_decomp_ranks0, _swift_stdlib_nfd_decomp_ranks1, _swift_stdlib_nfd_decomp_ranks2, - _swift_stdlib_nfd_decomp_ranks3, _swift_stdlib_nfd_decomp_ranks4, _swift_stdlib_nfd_decomp_ranks5, - _swift_stdlib_nfd_decomp_ranks6, _swift_stdlib_nfd_decomp_ranks7, _swift_stdlib_nfd_decomp_ranks8, - _swift_stdlib_nfd_decomp_ranks9, _swift_stdlib_nfd_decomp_ranks10, -}; - -static const uint8_t _swift_stdlib_nfd_decomp[9435] = { - 0x4, 0xF0, 0xA4, 0xBE, 0xA1, 0x3, 0x69, 0xCC, 0x82, 0x3, 0x5A, 0xCC, 0xB1, 0x3, 0xE5, 0xBD, 0x93, - 0x3, 0xE7, 0x80, 0x9E, 0x3, 0xE5, 0xB5, 0xAB, 0x6, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0xE5, - 0xAC, 0xBE, 0x3, 0xE8, 0xB7, 0x8B, 0x5, 0x41, 0xCC, 0x82, 0xCC, 0x80, 0x6, 0xE3, 0x81, 0xB8, 0xE3, - 0x82, 0x9A, 0x3, 0xE7, 0x8E, 0x87, 0x3, 0xE7, 0x91, 0xB1, 0x3, 0x55, 0xCC, 0x88, 0x3, 0xE8, 0x91, - 0x89, 0x3, 0xE9, 0xA7, 0xB1, 0x3, 0xE4, 0x95, 0x9D, 0x5, 0x61, 0xCC, 0x82, 0xCC, 0x81, 0x3, 0x63, - 0xCC, 0x87, 0x6, 0xE0, 0xA4, 0xA2, 0xE0, 0xA4, 0xBC, 0x4, 0xD7, 0xA1, 0xD6, 0xBC, 0x3, 0xE5, 0xBE, - 0xAD, 0x8, 0xF0, 0x91, 0x8D, 0x87, 0xF0, 0x91, 0x8C, 0xBE, 0x3, 0xE8, 0x8A, 0x9D, 0x3, 0xE5, 0x8B, - 0xBA, 0x6, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85, 0x5, 0xE2, 0xAB, 0x9D, 0xCC, 0xB8, 0x3, 0xE4, 0xA9, - 0xB6, 0x3, 0x75, 0xCC, 0x9B, 0x3, 0x43, 0xCC, 0x82, 0x3, 0x43, 0xCC, 0xA7, 0x3, 0xE6, 0x8E, 0x83, - 0x3, 0xE6, 0x86, 0xB2, 0x4, 0xCE, 0xBF, 0xCC, 0x81, 0x3, 0xE9, 0x99, 0x8B, 0x3, 0x6F, 0xCC, 0x80, - 0x4, 0xF0, 0xAA, 0x8A, 0x91, 0x3, 0xE4, 0xBB, 0xA4, 0x3, 0xE3, 0xAE, 0x9D, 0x3, 0xE6, 0x96, 0x99, - 0x3, 0xE8, 0x90, 0xBD, 0x5, 0x45, 0xCC, 0x82, 0xCC, 0x89, 0x3, 0xE9, 0x9D, 0x96, 0x3, 0xE8, 0xA6, - 0x96, 0x4, 0xCE, 0x99, 0xCC, 0x94, 0x3, 0x6F, 0xCC, 0xA3, 0x3, 0xE8, 0x9A, 0x88, 0x3, 0xE5, 0x93, - 0xB6, 0x6, 0xE0, 0xA4, 0x97, 0xE0, 0xA4, 0xBC, 0x3, 0xE3, 0xBC, 0x9B, 0x3, 0x4F, 0xCC, 0x88, 0x4, - 0xCE, 0x9F, 0xCC, 0x81, 0x4, 0xD7, 0xB2, 0xD6, 0xB7, 0x3, 0xE4, 0xA7, 0xA6, 0x8, 0xCE, 0x97, 0xCC, - 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x8, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE5, - 0x8D, 0xB3, 0x3, 0xE6, 0x90, 0x9C, 0x4, 0xF0, 0xA3, 0xBB, 0x91, 0x3, 0xE8, 0x8C, 0xA3, 0x3, 0xE5, - 0xA3, 0x9F, 0x4, 0xF0, 0xA4, 0x8B, 0xAE, 0x3, 0xE6, 0x9C, 0x80, 0x3, 0x69, 0xCC, 0xA8, 0x3, 0x67, - 0xCC, 0x82, 0x3, 0x47, 0xCC, 0x84, 0x3, 0x4F, 0xCC, 0x8C, 0x5, 0x55, 0xCC, 0x9B, 0xCC, 0x80, 0x3, - 0xE9, 0xA6, 0xA7, 0x3, 0x75, 0xCC, 0x8C, 0x3, 0xE4, 0x80, 0x98, 0x6, 0xE1, 0xAC, 0x91, 0xE1, 0xAC, - 0xB5, 0x3, 0xE7, 0xB8, 0x89, 0x6, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x80, 0x6, 0xE0, 0xA4, 0x95, 0xE0, - 0xA4, 0xBC, 0x3, 0xE7, 0xA7, 0x8A, 0x3, 0xE4, 0x84, 0xAF, 0x3, 0xE5, 0xB3, 0x80, 0x3, 0xE7, 0x81, - 0xBD, 0x3, 0x4F, 0xCC, 0x80, 0x3, 0xE7, 0xA5, 0x9D, 0x3, 0xE8, 0xA3, 0xA1, 0x4, 0xD0, 0x95, 0xCC, - 0x88, 0x3, 0xE8, 0xAB, 0x8B, 0x4, 0xCE, 0xA5, 0xCC, 0x88, 0x3, 0xE9, 0x85, 0xAA, 0x4, 0xF0, 0xA8, - 0xB5, 0xB7, 0x3, 0xE5, 0x8D, 0xBD, 0x5, 0x4F, 0xCC, 0x84, 0xCC, 0x81, 0x3, 0x61, 0xCC, 0x8A, 0x6, - 0xE0, 0xA4, 0xAF, 0xE0, 0xA4, 0xBC, 0x6, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x82, 0x3, 0xE5, 0xA7, - 0x98, 0x6, 0xE0, 0xA6, 0xA1, 0xE0, 0xA6, 0xBC, 0x5, 0x4F, 0xCC, 0x83, 0xCC, 0x81, 0x3, 0x6F, 0xCC, - 0x8F, 0x6, 0xE0, 0xA7, 0x87, 0xE0, 0xA6, 0xBE, 0x3, 0xE7, 0x8E, 0xB2, 0x3, 0xE4, 0x81, 0x86, 0x3, - 0xE8, 0xA6, 0x86, 0x3, 0xE5, 0x87, 0x9E, 0x3, 0xE9, 0xBC, 0x8F, 0x3, 0x4F, 0xCC, 0x91, 0x3, 0xE9, - 0xA4, 0xA8, 0x3, 0xE6, 0x83, 0x87, 0x3, 0x4B, 0xCC, 0x81, 0x3, 0x65, 0xCC, 0x88, 0x3, 0xE5, 0x8B, - 0xA4, 0x3, 0x49, 0xCC, 0x8C, 0x3, 0xE4, 0x95, 0xA1, 0x3, 0xE6, 0xB1, 0x8E, 0x4, 0xC3, 0xA6, 0xCC, - 0x84, 0x9, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8F, 0xE0, 0xB7, 0x8A, 0x3, 0x6E, 0xCC, 0x83, 0x6, 0xCE, - 0x91, 0xCC, 0x93, 0xCD, 0x82, 0x3, 0x55, 0xCC, 0x80, 0x3, 0xE5, 0x96, 0xAB, 0x3, 0xE4, 0x95, 0xAB, - 0x3, 0xE5, 0xB9, 0xB4, 0x3, 0xE6, 0xB2, 0xBF, 0x3, 0x59, 0xCC, 0x87, 0x5, 0x4F, 0xCC, 0x9B, 0xCC, - 0x89, 0x3, 0xE7, 0x9C, 0x9E, 0x3, 0xE4, 0xBA, 0x82, 0x4, 0xC2, 0xA8, 0xCD, 0x82, 0x6, 0xCE, 0x97, - 0xCC, 0x94, 0xCD, 0x85, 0x3, 0xE8, 0x99, 0xA9, 0x3, 0xE5, 0xBC, 0xA2, 0x3, 0xE8, 0xAA, 0xA0, 0x6, - 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x9A, 0x3, 0x77, 0xCC, 0x81, 0x6, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, - 0x81, 0x4, 0xCF, 0x85, 0xCC, 0x81, 0x3, 0xE7, 0x9B, 0xB4, 0x3, 0xE5, 0xAC, 0xA8, 0x3, 0xE5, 0x8B, - 0xB5, 0x3, 0x42, 0xCC, 0xA3, 0x3, 0xE8, 0xB6, 0xBC, 0x3, 0x4B, 0xCC, 0xA3, 0x3, 0xE4, 0xBE, 0x86, - 0x3, 0xE4, 0xAC, 0xB3, 0x6, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x82, 0x6, 0xE3, 0x81, 0xB2, 0xE3, 0x82, - 0x99, 0x3, 0xE7, 0xB4, 0xA2, 0x3, 0x75, 0xCC, 0xAD, 0x4, 0xD0, 0xA3, 0xCC, 0x84, 0x3, 0xE9, 0xBA, - 0xBB, 0x3, 0xE8, 0xAB, 0xB8, 0x4, 0xC3, 0x86, 0xCC, 0x81, 0x3, 0x61, 0xCC, 0x86, 0x3, 0xE3, 0x92, - 0x9E, 0x3, 0xE6, 0x91, 0xBE, 0x5, 0x4F, 0xCC, 0x87, 0xCC, 0x84, 0x3, 0x53, 0xCC, 0x81, 0x3, 0xE6, - 0x8B, 0x89, 0x3, 0x6E, 0xCC, 0x81, 0x8, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x6, 0xCE, - 0xB9, 0xCC, 0x94, 0xCC, 0x81, 0x6, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x85, 0x3, 0x41, 0xCC, 0xA8, 0x3, - 0xE9, 0x8B, 0x98, 0x5, 0x61, 0xCC, 0x86, 0xCC, 0x81, 0x6, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81, 0x4, - 0xCE, 0xB5, 0xCC, 0x94, 0x3, 0xE8, 0x93, 0xAE, 0x3, 0xE9, 0xBB, 0xB9, 0x3, 0x6C, 0xCC, 0xB1, 0x5, - 0x41, 0xCC, 0xA3, 0xCC, 0x82, 0x3, 0xE7, 0x91, 0x87, 0x3, 0xE7, 0xB7, 0xB4, 0x3, 0xE6, 0x8D, 0xA8, - 0x3, 0x49, 0xCC, 0x82, 0x3, 0x6A, 0xCC, 0x8C, 0x3, 0xE5, 0x8B, 0x87, 0x5, 0x65, 0xCC, 0x84, 0xCC, - 0x80, 0x6, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x9F, 0x4, 0xF0, 0xA1, 0x93, 0xA4, 0x3, 0xE7, 0x9D, 0x80, - 0x3, 0x41, 0xCC, 0x87, 0x3, 0xE7, 0x90, 0x89, 0x3, 0xE5, 0xB1, 0xA2, 0x4, 0xDB, 0x81, 0xD9, 0x94, - 0x6, 0xCE, 0xB1, 0xCC, 0x80, 0xCD, 0x85, 0x6, 0xE0, 0xAF, 0x86, 0xE0, 0xAF, 0x97, 0x4, 0xF0, 0xA0, - 0x94, 0x9C, 0x4, 0xCE, 0xB9, 0xCC, 0x81, 0x3, 0xE5, 0x95, 0x95, 0x6, 0xCE, 0x97, 0xCC, 0x93, 0xCC, - 0x80, 0x3, 0xE9, 0xB9, 0xBF, 0x4, 0xD8, 0xA7, 0xD9, 0x95, 0x3, 0x46, 0xCC, 0x87, 0x3, 0xE7, 0x82, - 0xAD, 0x3, 0xE7, 0xB2, 0x92, 0x3, 0xE7, 0x9B, 0x9B, 0x4, 0xF0, 0xA9, 0x92, 0x96, 0x3, 0xE6, 0x97, - 0xA3, 0x3, 0xE4, 0xAA, 0xB2, 0x3, 0x73, 0xCC, 0x8C, 0x3, 0x61, 0xCC, 0x87, 0x4, 0xD7, 0x98, 0xD6, - 0xBC, 0x3, 0xE9, 0x9B, 0x83, 0x5, 0x73, 0xCC, 0x81, 0xCC, 0x87, 0x3, 0xE9, 0x96, 0x8B, 0x3, 0xE7, - 0xBD, 0xB9, 0x3, 0xE5, 0x8D, 0x91, 0x3, 0xE8, 0x98, 0xAD, 0x3, 0xE7, 0xA2, 0x8C, 0x3, 0x7A, 0xCC, - 0xB1, 0x3, 0x45, 0xCC, 0x91, 0x6, 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99, 0x3, 0xE4, 0xB8, 0xB8, 0x3, - 0xE4, 0xBA, 0xAE, 0x6, 0xE0, 0xA7, 0x87, 0xE0, 0xA7, 0x97, 0x3, 0xE4, 0xBD, 0xA0, 0x8, 0xCE, 0xA9, - 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0x3, 0x7A, 0xCC, 0x82, 0x3, 0xE5, 0xB1, 0xAE, 0x5, 0xE2, 0x89, - 0xB6, 0xCC, 0xB8, 0x3, 0xE5, 0xA0, 0xB2, 0x5, 0xE1, 0xBF, 0xBE, 0xCC, 0x81, 0x3, 0xE6, 0x83, 0xA1, - 0x4, 0xF0, 0xA9, 0x88, 0x9A, 0x3, 0xE8, 0x97, 0x8D, 0x3, 0x49, 0xCC, 0x87, 0x4, 0xCE, 0x9F, 0xCC, - 0x80, 0x3, 0xE9, 0xBB, 0x8E, 0x3, 0xE9, 0x99, 0xB8, 0x3, 0xE7, 0x95, 0x99, 0x3, 0xE5, 0xBB, 0x99, - 0x3, 0xE9, 0xB7, 0xBA, 0x4, 0xCE, 0x91, 0xCC, 0x81, 0x6, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0x4, - 0xF0, 0xA2, 0x8C, 0xB1, 0x3, 0xE8, 0xA5, 0x81, 0x3, 0x73, 0xCC, 0x81, 0x3, 0xE6, 0x8E, 0xA0, 0x3, - 0xE3, 0xA4, 0xBA, 0x3, 0xE6, 0x9C, 0x9B, 0x3, 0x5A, 0xCC, 0x82, 0x3, 0xE8, 0x87, 0xAD, 0x3, 0xE9, - 0x9D, 0x88, 0x3, 0xE5, 0x85, 0xA4, 0x3, 0xE7, 0xB6, 0xA0, 0x3, 0x59, 0xCC, 0x80, 0x3, 0xE5, 0xB5, - 0xBC, 0x3, 0xE8, 0xBE, 0xB6, 0x4, 0xF0, 0xA3, 0x8F, 0x83, 0x3, 0xE2, 0x80, 0x83, 0x3, 0x61, 0xCC, - 0xA8, 0x3, 0xE8, 0xA3, 0xBA, 0x4, 0xCE, 0xB7, 0xCC, 0x81, 0x3, 0xE7, 0xA6, 0x8E, 0x3, 0xE5, 0x88, - 0x87, 0x3, 0xE9, 0xBE, 0x8E, 0x3, 0xE7, 0x86, 0x9C, 0x3, 0xE5, 0xA4, 0x9A, 0x3, 0xE6, 0xAB, 0x93, - 0x3, 0xE6, 0xA2, 0x85, 0x6, 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82, 0x3, 0xE7, 0x95, 0xA5, 0x6, 0xCE, - 0xA9, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0xE4, 0x8C, 0xB4, 0x3, 0xE3, 0xAC, 0x99, 0x3, 0xE6, 0xB4, 0x96, - 0x3, 0xE6, 0x85, 0xA8, 0x3, 0xE6, 0x8B, 0x8F, 0x3, 0xE5, 0xB4, 0x99, 0x3, 0xE9, 0xAD, 0xAF, 0x6, - 0xE1, 0xAC, 0x8D, 0xE1, 0xAC, 0xB5, 0x5, 0xE2, 0x89, 0xB3, 0xCC, 0xB8, 0x4, 0xCE, 0xB9, 0xCC, - 0x84, 0x3, 0xE8, 0xB1, 0x88, 0x3, 0xE6, 0x97, 0x85, 0x4, 0xCE, 0xA9, 0xCC, 0x93, 0x4, 0xD0, 0xB0, - 0xCC, 0x86, 0x3, 0xE8, 0x88, 0x98, 0x3, 0xE6, 0xBB, 0x9B, 0x5, 0x55, 0xCC, 0x9B, 0xCC, 0x83, 0x3, - 0x59, 0xCC, 0x81, 0x4, 0xF0, 0xA6, 0x8B, 0x99, 0x3, 0xE8, 0x80, 0x85, 0x3, 0xE4, 0xA9, 0xAE, 0x3, - 0xE8, 0xBC, 0xA6, 0x6, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x85, 0x3, 0x69, 0xCC, 0x84, 0x3, 0xE6, 0x9D, - 0x9E, 0x6, 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82, 0x5, 0x45, 0xCC, 0xA3, 0xCC, 0x82, 0x4, 0xCF, 0x89, - 0xCC, 0x94, 0x6, 0xE0, 0xAF, 0x87, 0xE0, 0xAE, 0xBE, 0x4, 0xF0, 0xA3, 0x8E, 0x9C, 0x3, 0x45, 0xCC, - 0x8C, 0x3, 0xE7, 0xA4, 0xBE, 0x6, 0xE0, 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0x5, 0x52, 0xCC, 0xA3, 0xCC, - 0x84, 0x3, 0xE7, 0x9C, 0x9F, 0x6, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, 0x3, 0xE7, 0x8C, 0xAA, 0x3, - 0xE7, 0xB1, 0xBB, 0x6, 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x99, 0x5, 0x53, 0xCC, 0xA3, 0xCC, 0x87, 0x3, - 0xE8, 0xAA, 0xAA, 0x2, 0xCE, 0xA9, 0x3, 0xE5, 0x8C, 0x86, 0x4, 0xCF, 0x89, 0xCC, 0x81, 0x3, 0x4F, - 0xCC, 0x83, 0x5, 0xE2, 0x8A, 0xA9, 0xCC, 0xB8, 0x3, 0xE6, 0xB7, 0x8B, 0x3, 0x45, 0xCC, 0xAD, 0x3, - 0xE8, 0xBE, 0xB0, 0x4, 0xF0, 0xAA, 0x83, 0x8E, 0x3, 0x4E, 0xCC, 0xAD, 0x4, 0xD0, 0x98, 0xCC, 0x80, - 0x3, 0xE5, 0x88, 0xA9, 0x3, 0x41, 0xCC, 0x8F, 0x5, 0x4F, 0xCC, 0x9B, 0xCC, 0x81, 0x3, 0x4C, 0xCC, - 0x81, 0x5, 0x4F, 0xCC, 0x9B, 0xCC, 0x80, 0x6, 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x3, 0x61, 0xCC, - 0x83, 0x3, 0xE6, 0x82, 0x94, 0x6, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0x4, 0xCE, 0xB7, 0xCD, 0x82, - 0x3, 0xE4, 0xB5, 0x96, 0x3, 0xE9, 0x87, 0x91, 0x3, 0xE6, 0xAE, 0x9F, 0x3, 0x79, 0xCC, 0xA3, 0x8, - 0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE7, 0xA6, 0xAE, 0x6, 0xE3, 0x83, 0x98, - 0xE3, 0x82, 0x99, 0x5, 0x4F, 0xCC, 0x82, 0xCC, 0x89, 0x3, 0x45, 0xCC, 0x83, 0x3, 0x49, 0xCC, 0x81, - 0x6, 0xE0, 0xBD, 0x80, 0xE0, 0xBE, 0xB5, 0x3, 0xE5, 0x97, 0xA2, 0x3, 0xE7, 0x88, 0xAB, 0x3, 0xE7, - 0x95, 0xB0, 0x3, 0xE7, 0x94, 0xA4, 0x3, 0xE7, 0xB0, 0xBE, 0x3, 0xE9, 0x9B, 0xA2, 0x3, 0x41, 0xCC, - 0x81, 0x6, 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x85, 0x4, 0xD0, 0x9E, 0xCC, 0x88, 0x4, 0xF0, 0xA8, 0x9C, - 0xAE, 0x4, 0xD1, 0xB5, 0xCC, 0x8F, 0x3, 0xE8, 0x9D, 0xB9, 0x3, 0xE5, 0x86, 0x95, 0x6, 0xE3, 0x83, - 0x92, 0xE3, 0x82, 0x9A, 0x3, 0x45, 0xCC, 0x82, 0x3, 0xE3, 0xA1, 0xA2, 0x3, 0xE6, 0x86, 0x8E, 0x3, - 0x41, 0xCC, 0x91, 0x3, 0xE5, 0xB5, 0xAE, 0x4, 0xD3, 0xA8, 0xCC, 0x88, 0x3, 0xE9, 0x80, 0xB8, 0x3, - 0x69, 0xCC, 0x8C, 0x3, 0xE6, 0x95, 0x8F, 0x4, 0xF0, 0xA6, 0x87, 0x9A, 0x4, 0xF0, 0xA4, 0x9C, 0xB5, - 0x3, 0xE9, 0x96, 0xB7, 0x3, 0xE8, 0xBB, 0x94, 0x4, 0xCE, 0x91, 0xCC, 0x84, 0x3, 0x79, 0xCC, 0x89, - 0x6, 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99, 0x3, 0x58, 0xCC, 0x88, 0x3, 0x65, 0xCC, 0xAD, 0x5, 0x4F, - 0xCC, 0x84, 0xCC, 0x80, 0x4, 0xC5, 0xBF, 0xCC, 0x87, 0x6, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x85, 0x3, - 0xE6, 0xA4, 0x94, 0x3, 0x6C, 0xCC, 0x8C, 0x5, 0x75, 0xCC, 0x88, 0xCC, 0x80, 0x5, 0x4F, 0xCC, 0x9B, - 0xCC, 0x83, 0x3, 0xE6, 0xAE, 0xBA, 0x4, 0xF0, 0xA5, 0xAA, 0xA7, 0x3, 0xE8, 0x8A, 0xBD, 0x3, 0x57, - 0xCC, 0xA3, 0x8, 0xF0, 0x91, 0x82, 0xA5, 0xF0, 0x91, 0x82, 0xBA, 0x3, 0xE6, 0xB1, 0xA7, 0x6, 0xE0, - 0xA8, 0xB8, 0xE0, 0xA8, 0xBC, 0x3, 0x7A, 0xCC, 0xA3, 0x3, 0xE5, 0xBF, 0x97, 0x4, 0xF0, 0xA1, 0xB7, - 0xA6, 0x4, 0xC3, 0xB8, 0xCC, 0x81, 0x3, 0x72, 0xCC, 0x8F, 0x5, 0x65, 0xCC, 0x84, 0xCC, 0x81, 0x3, - 0x43, 0xCC, 0x81, 0x3, 0xE8, 0x94, 0x96, 0x5, 0x55, 0xCC, 0x9B, 0xCC, 0x81, 0x3, 0xE9, 0x88, 0xB8, - 0x4, 0xCE, 0xA5, 0xCC, 0x84, 0x3, 0xE4, 0x98, 0xB5, 0x3, 0xE6, 0xAD, 0xB7, 0x3, 0xE5, 0x86, 0x8D, - 0x4, 0xD0, 0xB0, 0xCC, 0x88, 0x4, 0xC2, 0xA8, 0xCC, 0x81, 0x3, 0x64, 0xCC, 0xAD, 0x3, 0x69, 0xCC, - 0x89, 0x3, 0xE4, 0xBE, 0x80, 0x4, 0xD7, 0xA8, 0xD6, 0xBC, 0x6, 0xCE, 0xB7, 0xCC, 0x80, 0xCD, 0x85, - 0x4, 0xF0, 0xA7, 0xA2, 0xAE, 0x4, 0xD0, 0xB8, 0xCC, 0x86, 0x3, 0xE8, 0xB7, 0xAF, 0x3, 0x74, 0xCC, - 0xA7, 0x3, 0x65, 0xCC, 0xA3, 0x4, 0xF0, 0xA6, 0x8C, 0xBE, 0x5, 0x45, 0xCC, 0xA7, 0xCC, 0x86, 0x4, - 0xD9, 0x88, 0xD9, 0x94, 0x3, 0xE7, 0xBD, 0xBA, 0x3, 0xE5, 0xB0, 0x86, 0x5, 0xE2, 0x89, 0xA1, 0xCC, - 0xB8, 0x3, 0xE5, 0xB7, 0xA2, 0x4, 0xD7, 0x90, 0xD6, 0xB8, 0x3, 0xE8, 0x8B, 0xA5, 0x4, 0xCE, 0xB1, - 0xCD, 0x85, 0x3, 0x68, 0xCC, 0x8C, 0x3, 0xE5, 0x96, 0x9D, 0x3, 0xE5, 0xB6, 0xB2, 0x3, 0xE7, 0xB5, - 0xA3, 0x3, 0xE9, 0x86, 0x99, 0x3, 0xE9, 0x83, 0xBD, 0x6, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0x3, - 0xE9, 0x84, 0x91, 0x4, 0xF0, 0xA2, 0xAF, 0xB1, 0x3, 0xE6, 0x88, 0xAE, 0x3, 0x69, 0xCC, 0x88, 0x3, - 0x4C, 0xCC, 0x8C, 0x3, 0x65, 0xCC, 0x89, 0x6, 0xCE, 0x99, 0xCC, 0x94, 0xCD, 0x82, 0x3, 0xE5, 0x89, - 0xB2, 0x6, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x80, 0x3, 0x73, 0xCC, 0xA7, 0x3, 0xE9, 0x89, 0xBC, 0x4, - 0xF0, 0xA3, 0xB4, 0x9E, 0x6, 0xE0, 0xA4, 0x9C, 0xE0, 0xA4, 0xBC, 0x3, 0xE7, 0xBE, 0x9A, 0x5, 0x61, - 0xCC, 0x88, 0xCC, 0x84, 0x3, 0xE6, 0xB3, 0xA5, 0x3, 0x45, 0xCC, 0x86, 0x6, 0xE3, 0x82, 0xAF, 0xE3, - 0x82, 0x99, 0x5, 0x41, 0xCC, 0x86, 0xCC, 0x89, 0x3, 0xE6, 0x87, 0xB6, 0x3, 0xE6, 0x95, 0xAC, 0x3, - 0xE5, 0x87, 0x9C, 0x6, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0x99, 0x3, 0x75, 0xCC, 0xB0, 0x3, 0xE5, 0x86, - 0x92, 0x5, 0x6F, 0xCC, 0xA8, 0xCC, 0x84, 0x5, 0x55, 0xCC, 0x88, 0xCC, 0x8C, 0x4, 0xCE, 0x91, 0xCC, - 0x93, 0x8, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE8, 0xA3, 0x82, 0x3, 0x72, 0xCC, - 0x81, 0x3, 0xE9, 0xA7, 0xBE, 0x4, 0xDB, 0x95, 0xD9, 0x94, 0x3, 0x44, 0xCC, 0x87, 0x3, 0x55, 0xCC, - 0xB0, 0x6, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x80, 0x3, 0x74, 0xCC, 0x88, 0x3, 0x53, 0xCC, 0x8C, 0x3, - 0xE8, 0x93, 0xB1, 0x8, 0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x3, 0x4A, 0xCC, 0x82, 0x3, - 0xE6, 0x92, 0x9A, 0x6, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x80, 0x3, 0xE5, 0xAF, 0xAE, 0x6, 0xE0, 0xBD, - 0x96, 0xE0, 0xBE, 0xB7, 0x4, 0xD7, 0x99, 0xD6, 0xBC, 0x2, 0xCE, 0xB9, 0x6, 0xE1, 0xAD, 0x82, 0xE1, - 0xAC, 0xB5, 0x3, 0xE8, 0x89, 0xB9, 0x3, 0x55, 0xCC, 0x89, 0x3, 0xE8, 0x8D, 0x92, 0x3, 0x52, 0xCC, - 0x87, 0x3, 0xE5, 0xB5, 0x90, 0x3, 0xE8, 0x82, 0x8B, 0x3, 0x54, 0xCC, 0xA7, 0x3, 0xE9, 0x82, 0x94, - 0x4, 0xF0, 0xA6, 0xB3, 0x95, 0x2, 0xC2, 0xB4, 0x4, 0xF0, 0xA2, 0x86, 0x9F, 0x3, 0xE6, 0x8B, 0x93, - 0x4, 0xD0, 0xB3, 0xCC, 0x81, 0x3, 0xE5, 0xA5, 0xB3, 0x3, 0xE7, 0x87, 0x90, 0x3, 0xE5, 0xBD, 0xA9, - 0x3, 0xE7, 0x88, 0x9B, 0x3, 0xE9, 0xBC, 0x85, 0x3, 0xE4, 0x8D, 0x99, 0x3, 0xE5, 0xAA, 0xB5, 0x6, - 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8A, 0x4, 0xD7, 0xA7, 0xD6, 0xBC, 0x6, 0xCE, 0xB9, 0xCC, 0x93, - 0xCC, 0x81, 0x4, 0xF0, 0xA0, 0x95, 0x8B, 0x4, 0xF0, 0xA4, 0xB0, 0xB6, 0x4, 0xF0, 0xA6, 0xB5, 0xAB, - 0x3, 0xE9, 0x83, 0x8E, 0x3, 0xE7, 0x89, 0xA2, 0x3, 0x4F, 0xCC, 0x84, 0x3, 0x65, 0xCC, 0x81, 0x3, - 0x76, 0xCC, 0x83, 0x4, 0xCE, 0xB1, 0xCC, 0x86, 0x4, 0xF0, 0xA8, 0x97, 0x92, 0x5, 0x65, 0xCC, 0x82, - 0xCC, 0x80, 0x2, 0xCC, 0x81, 0x3, 0x55, 0xCC, 0x81, 0x3, 0xE5, 0x80, 0xAB, 0x5, 0x41, 0xCC, 0x82, - 0xCC, 0x81, 0x4, 0xCE, 0xA9, 0xCD, 0x85, 0x5, 0x53, 0xCC, 0x8C, 0xCC, 0x87, 0x5, 0x6F, 0xCC, 0x9B, - 0xCC, 0x83, 0x3, 0x49, 0xCC, 0xA8, 0x3, 0xE7, 0xA4, 0xAA, 0x4, 0xF0, 0xA4, 0xBE, 0xB8, 0x3, 0x64, - 0xCC, 0xA3, 0x6, 0xE0, 0xB5, 0x86, 0xE0, 0xB5, 0x97, 0x3, 0x42, 0xCC, 0xB1, 0x3, 0xE8, 0xA1, 0xA0, - 0x3, 0xE9, 0x9F, 0xBF, 0x3, 0xE7, 0x9D, 0x8A, 0x6, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x80, 0x3, 0xE9, - 0x8D, 0x8A, 0x3, 0xE6, 0xB5, 0xB7, 0x6, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0x3, 0xE3, 0x92, 0xBB, - 0x3, 0xE7, 0xA3, 0x8A, 0x3, 0xE6, 0xB8, 0x9A, 0x3, 0xE6, 0xB4, 0x9B, 0x3, 0xE9, 0xA0, 0xBB, 0x5, - 0x55, 0xCC, 0x9B, 0xCC, 0xA3, 0x3, 0xE5, 0x94, 0x90, 0x3, 0xE8, 0xAE, 0x8A, 0x3, 0x6F, 0xCC, 0x91, - 0x4, 0xCE, 0xB5, 0xCC, 0x81, 0x5, 0x65, 0xCC, 0xA3, 0xCC, 0x82, 0x4, 0xCE, 0xA9, 0xCC, 0x81, 0x4, - 0xC2, 0xA8, 0xCC, 0x80, 0x3, 0xE7, 0xA5, 0x89, 0x3, 0xE9, 0xBA, 0x9F, 0x3, 0xE6, 0xB5, 0xAA, 0x3, - 0xE7, 0xB8, 0x82, 0x6, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x3, 0xE4, 0x8F, 0x95, 0x3, 0x65, 0xCC, - 0x8C, 0x3, 0xE7, 0xA3, 0x8C, 0x3, 0xE5, 0xB0, 0xBF, 0x3, 0xE8, 0xBD, 0xA2, 0x3, 0xE8, 0xB1, 0x95, - 0x5, 0xE2, 0x89, 0xB2, 0xCC, 0xB8, 0x3, 0xE6, 0xB4, 0x9E, 0x8, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x82, - 0xCD, 0x85, 0x4, 0xCE, 0x91, 0xCC, 0x80, 0x3, 0xE5, 0xBB, 0x8A, 0x5, 0xE1, 0xBE, 0xBF, 0xCC, 0x80, - 0x4, 0xF0, 0xA3, 0x9A, 0xA3, 0x4, 0xF0, 0xA3, 0x8A, 0xB8, 0x3, 0xE8, 0x8A, 0xB1, 0x5, 0x75, 0xCC, - 0x84, 0xCC, 0x88, 0x3, 0xE5, 0xA0, 0x8D, 0x3, 0xE5, 0xA8, 0x9B, 0x5, 0xE2, 0x8A, 0xAB, 0xCC, 0xB8, - 0x4, 0xD7, 0x9A, 0xD6, 0xBC, 0x3, 0x59, 0xCC, 0x82, 0x3, 0xE5, 0xB2, 0x8D, 0x3, 0x45, 0xCC, 0x89, - 0x3, 0xE9, 0x81, 0xB2, 0x3, 0xE8, 0xB4, 0x9B, 0x3, 0x75, 0xCC, 0x83, 0x3, 0x4E, 0xCC, 0x81, 0x6, - 0xE0, 0xBD, 0x91, 0xE0, 0xBE, 0xB7, 0x3, 0x73, 0xCC, 0xA3, 0x3, 0xE6, 0xB5, 0x81, 0x3, 0xE9, 0xA0, - 0x8B, 0x3, 0x4B, 0xCC, 0xB1, 0x4, 0xF0, 0xA8, 0x97, 0xAD, 0x4, 0xCE, 0x91, 0xCD, 0x85, 0x3, 0xE6, - 0x84, 0x88, 0x3, 0xE7, 0x9B, 0x8A, 0x5, 0xE2, 0x89, 0xBD, 0xCC, 0xB8, 0x3, 0xE9, 0x8F, 0xB9, 0x3, - 0xE5, 0xBC, 0x84, 0x3, 0x61, 0xCC, 0x88, 0x3, 0xE5, 0x87, 0x89, 0x3, 0xE9, 0x9B, 0xB6, 0x3, 0xE9, - 0xBE, 0x9C, 0x3, 0x52, 0xCC, 0xA7, 0x8, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x3, 0x4F, - 0xCC, 0x86, 0x3, 0xE6, 0x99, 0xB4, 0x8, 0xF0, 0x91, 0x96, 0xB9, 0xF0, 0x91, 0x96, 0xAF, 0x3, 0x73, - 0xCC, 0x82, 0x3, 0xE7, 0x85, 0x89, 0x3, 0xE4, 0xBE, 0xAE, 0x5, 0x53, 0xCC, 0x81, 0xCC, 0x87, 0x3, - 0xE6, 0xA7, 0xAA, 0x3, 0x53, 0xCC, 0xA7, 0x3, 0x53, 0xCC, 0xA6, 0x3, 0xE9, 0x8C, 0x84, 0x4, 0xCF, - 0x85, 0xCC, 0x86, 0x4, 0xD0, 0xA3, 0xCC, 0x88, 0x3, 0xE8, 0x84, 0xBE, 0x6, 0xCF, 0x85, 0xCC, 0x93, - 0xCC, 0x81, 0x3, 0xE6, 0xB4, 0xB4, 0x3, 0xE5, 0x88, 0xBA, 0x3, 0xE5, 0x91, 0xA8, 0x3, 0x54, 0xCC, - 0xA3, 0x3, 0xE8, 0x91, 0x97, 0x3, 0xE5, 0xA0, 0xB1, 0x3, 0xE7, 0xAB, 0x8B, 0x4, 0xCE, 0xA5, 0xCC, - 0x81, 0x3, 0x48, 0xCC, 0xAE, 0x3, 0x62, 0xCC, 0x87, 0x3, 0x55, 0xCC, 0xA3, 0x5, 0x73, 0xCC, 0x8C, - 0xCC, 0x87, 0x3, 0xE5, 0x8F, 0x8A, 0x4, 0xCE, 0x97, 0xCC, 0x94, 0x3, 0x47, 0xCC, 0x87, 0x3, 0xE5, - 0xBA, 0xB6, 0x3, 0xE5, 0x85, 0xA9, 0x3, 0xE8, 0x82, 0xAD, 0x3, 0xE8, 0x95, 0xA4, 0x3, 0xE8, 0xAB, - 0xAD, 0x3, 0xE8, 0x8F, 0x8C, 0x4, 0xCF, 0x89, 0xCC, 0x93, 0x3, 0xE5, 0xAF, 0x98, 0x6, 0xE3, 0x81, - 0xAF, 0xE3, 0x82, 0x9A, 0x3, 0xE8, 0x89, 0xAF, 0x6, 0xE3, 0x83, 0xB2, 0xE3, 0x82, 0x99, 0x3, 0xE9, - 0xBA, 0x97, 0x3, 0x72, 0xCC, 0xB1, 0x3, 0xE5, 0x90, 0xB8, 0x3, 0xE7, 0x8D, 0xB5, 0x3, 0xE5, 0x8F, - 0x83, 0x4, 0xCE, 0xB7, 0xCC, 0x94, 0x3, 0x6B, 0xCC, 0xB1, 0x3, 0xE7, 0xB3, 0x92, 0x3, 0x67, 0xCC, - 0x86, 0x3, 0x75, 0xCC, 0x88, 0x3, 0xE9, 0x87, 0x8F, 0x3, 0xE6, 0xBD, 0xAE, 0x3, 0xE9, 0x88, 0xB4, - 0x4, 0xF0, 0xA6, 0x9E, 0xA7, 0x3, 0xE3, 0xBF, 0xBC, 0x4, 0xF0, 0xA1, 0xAC, 0x98, 0x3, 0x41, 0xCC, - 0x89, 0x4, 0xF0, 0xA7, 0xA5, 0xA6, 0x3, 0xE7, 0xB4, 0x90, 0x3, 0xE7, 0x80, 0x9B, 0x3, 0xE5, 0x85, - 0xAD, 0x8, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x4, 0xD0, 0xB8, 0xCC, 0x84, 0x3, 0xE8, - 0x9E, 0xBA, 0x3, 0xE8, 0x9C, 0x8E, 0x3, 0xE6, 0xBF, 0xBE, 0x3, 0xE4, 0x88, 0x82, 0x3, 0xE6, 0x9A, - 0x91, 0x3, 0x6F, 0xCC, 0x81, 0x4, 0xF0, 0xA9, 0xAC, 0xB0, 0x3, 0x79, 0xCC, 0x84, 0x3, 0x43, 0xCC, - 0x8C, 0x4, 0xD1, 0x8B, 0xCC, 0x88, 0x3, 0xE8, 0x8C, 0xB6, 0x4, 0xF0, 0xA6, 0x9E, 0xB5, 0x5, 0x43, - 0xCC, 0xA7, 0xCC, 0x81, 0x8, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x3, 0xE7, 0xB8, - 0xB7, 0x4, 0xD7, 0x96, 0xD6, 0xBC, 0x3, 0x48, 0xCC, 0x82, 0x6, 0xE0, 0xBD, 0x82, 0xE0, 0xBE, 0xB7, - 0x3, 0x68, 0xCC, 0xA3, 0x3, 0x45, 0xCC, 0x88, 0x3, 0xE9, 0x84, 0x9B, 0x6, 0xCE, 0xA5, 0xCC, 0x94, - 0xCC, 0x81, 0x3, 0xE8, 0xA3, 0x9E, 0x3, 0x76, 0xCC, 0xA3, 0x3, 0xE8, 0x99, 0x9C, 0x4, 0xD7, 0x9B, - 0xD6, 0xBF, 0x5, 0x75, 0xCC, 0x9B, 0xCC, 0x83, 0x3, 0x5A, 0xCC, 0xA3, 0x3, 0xE7, 0x94, 0xBE, 0x3, - 0xE6, 0x8B, 0xBC, 0x3, 0xE5, 0xA5, 0x91, 0x3, 0xE6, 0x9C, 0x97, 0x3, 0xE5, 0x96, 0xB3, 0x4, 0xC3, - 0x98, 0xCC, 0x81, 0x4, 0xCE, 0x95, 0xCC, 0x94, 0x6, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0x8, 0xF0, - 0x91, 0x82, 0x99, 0xF0, 0x91, 0x82, 0xBA, 0x3, 0xE8, 0xA5, 0xA4, 0x3, 0x41, 0xCC, 0x86, 0x3, 0xE5, - 0x82, 0x99, 0x5, 0x6F, 0xCC, 0x82, 0xCC, 0x83, 0x4, 0xF0, 0xA9, 0x87, 0x9F, 0x3, 0x47, 0xCC, 0x82, - 0x6, 0xE0, 0xAE, 0x92, 0xE0, 0xAF, 0x97, 0x5, 0x75, 0xCC, 0x9B, 0xCC, 0x80, 0x5, 0x75, 0xCC, 0x88, - 0xCC, 0x81, 0x6, 0xE1, 0xAC, 0x89, 0xE1, 0xAC, 0xB5, 0x3, 0x41, 0xCC, 0x88, 0x4, 0xF0, 0xA2, 0xA1, - 0x8A, 0x3, 0x45, 0xCC, 0xA8, 0x3, 0xE8, 0x9E, 0x86, 0x3, 0xE6, 0x8C, 0xBD, 0x3, 0xE9, 0x9F, 0xA0, - 0x3, 0xE5, 0xAF, 0xB3, 0x3, 0xE5, 0x96, 0x99, 0x3, 0xE5, 0xAF, 0x83, 0x4, 0xCE, 0x95, 0xCC, 0x80, - 0x8, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x3, 0xE6, 0x8F, 0xA4, 0x3, 0xE5, 0xA4, 0xA2, - 0x8, 0xF0, 0x91, 0x8D, 0x87, 0xF0, 0x91, 0x8D, 0x97, 0x3, 0x74, 0xCC, 0x8C, 0x3, 0xE4, 0x94, 0xAB, - 0x3, 0x63, 0xCC, 0xA7, 0x3, 0xE8, 0x88, 0x84, 0x3, 0xE5, 0x87, 0xB5, 0x3, 0xE7, 0xA3, 0xBB, 0x3, - 0x7A, 0xCC, 0x81, 0x4, 0xF0, 0xA5, 0x90, 0x9D, 0x3, 0xE5, 0xB5, 0x83, 0x3, 0xE5, 0x92, 0xBD, 0x3, - 0xE5, 0xB1, 0xA5, 0x3, 0x50, 0xCC, 0x81, 0x3, 0xE5, 0xBE, 0xA9, 0x3, 0xE5, 0xB0, 0xA2, 0x5, 0x6F, - 0xCC, 0x83, 0xCC, 0x81, 0x6, 0xE1, 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0x4, 0xD3, 0x98, 0xCC, 0x88, 0x3, - 0xE9, 0x90, 0x95, 0x3, 0xE5, 0x83, 0x9A, 0x3, 0xE4, 0x88, 0xA7, 0x3, 0x75, 0xCC, 0x8A, 0x3, 0xE7, - 0x8E, 0x8B, 0x6, 0xE1, 0xAC, 0x85, 0xE1, 0xAC, 0xB5, 0x3, 0x6A, 0xCC, 0x82, 0x3, 0xE6, 0x91, 0x92, - 0x6, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0x49, 0xCC, 0x86, 0x4, 0xCF, 0x92, 0xCC, 0x81, 0xC, - 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0x3, 0x52, 0xCC, 0x8F, - 0x4, 0xD0, 0x98, 0xCC, 0x88, 0x3, 0xE6, 0xBA, 0x9C, 0x3, 0xE3, 0xBA, 0xB8, 0x5, 0x6F, 0xCC, 0x9B, - 0xCC, 0x80, 0x8, 0xF0, 0x9D, 0x85, 0x97, 0xF0, 0x9D, 0x85, 0xA5, 0x3, 0xE5, 0x95, 0xA3, 0x2, 0xCC, - 0x93, 0x6, 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82, 0x3, 0xE5, 0x8A, 0x89, 0x9, 0xE0, 0xB3, 0x86, 0xE0, - 0xB3, 0x82, 0xE0, 0xB3, 0x95, 0x4, 0xF0, 0xA1, 0x9A, 0xA8, 0x3, 0x75, 0xCC, 0x8B, 0x3, 0x63, 0xCC, - 0x8C, 0x3, 0xE8, 0xA4, 0x90, 0x3, 0xE8, 0x8D, 0x93, 0x3, 0xE5, 0xBA, 0xB0, 0x3, 0x6F, 0xCC, 0x9B, - 0x3, 0xE5, 0xAF, 0xA7, 0x3, 0xE5, 0x86, 0xB5, 0x3, 0xE9, 0x83, 0x9E, 0x5, 0xE2, 0x88, 0x8B, 0xCC, - 0xB8, 0x3, 0x68, 0xCC, 0x82, 0x3, 0xE8, 0xA6, 0x8B, 0x6, 0xCE, 0xA5, 0xCC, 0x94, 0xCD, 0x82, 0x6, - 0xE1, 0x80, 0xA5, 0xE1, 0x80, 0xAE, 0x3, 0xE9, 0xA1, 0x9E, 0x3, 0xE5, 0xA5, 0x94, 0x3, 0x5A, 0xCC, - 0x87, 0x3, 0xE7, 0x88, 0xA8, 0x8, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0x5, 0x41, 0xCC, - 0xA3, 0xCC, 0x86, 0x3, 0xE3, 0xA8, 0xAE, 0x3, 0x4B, 0xCC, 0x8C, 0x6, 0xE0, 0xAF, 0x86, 0xE0, 0xAE, - 0xBE, 0x3, 0xE5, 0x85, 0xA7, 0x4, 0xD0, 0x98, 0xCC, 0x84, 0x6, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x82, - 0x6, 0xE0, 0xBD, 0xB1, 0xE0, 0xBD, 0xB2, 0x3, 0xE7, 0x85, 0xAE, 0x6, 0xCE, 0x91, 0xCC, 0x94, 0xCC, - 0x81, 0x5, 0x6F, 0xCC, 0x82, 0xCC, 0x89, 0x4, 0xF0, 0xA7, 0xB2, 0xA8, 0x5, 0x49, 0xCC, 0x88, 0xCC, - 0x81, 0x6, 0xE0, 0xAD, 0x87, 0xE0, 0xAC, 0xBE, 0x6, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x80, 0x4, 0xCE, - 0x95, 0xCC, 0x81, 0x3, 0xE9, 0x99, 0x8D, 0x3, 0xE9, 0x9A, 0x86, 0x4, 0xF0, 0xA5, 0x84, 0xB3, 0x4, - 0xD7, 0x9C, 0xD6, 0xBC, 0x3, 0xE5, 0xA3, 0xB7, 0x3, 0x3D, 0xCC, 0xB8, 0x4, 0xDB, 0x92, 0xD9, 0x94, - 0x8, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x4, 0xCE, 0xB9, 0xCD, 0x82, 0x3, 0xE4, 0xB3, - 0x8E, 0x6, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0x3, 0x55, 0xCC, 0x9B, 0x5, 0x6F, 0xCC, 0x9B, 0xCC, - 0xA3, 0x3, 0xE8, 0x99, 0x90, 0x8, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85, 0xA5, 0x4, 0xD8, 0xA7, - 0xD9, 0x93, 0x6, 0xE0, 0xBD, 0x8C, 0xE0, 0xBE, 0xB7, 0x3, 0x70, 0xCC, 0x81, 0x3, 0xE8, 0xBC, 0xBB, - 0x4, 0xF0, 0xA0, 0x84, 0xA2, 0x3, 0x55, 0xCC, 0x8F, 0x3, 0xE9, 0x98, 0xAE, 0x3, 0xE4, 0xB8, 0xB9, - 0x5, 0x61, 0xCC, 0x82, 0xCC, 0x80, 0x3, 0xE5, 0xA3, 0xB2, 0x3, 0x57, 0xCC, 0x87, 0x6, 0xE3, 0x81, - 0x9B, 0xE3, 0x82, 0x99, 0x4, 0xD1, 0x87, 0xCC, 0x88, 0x3, 0xE7, 0xBE, 0xBD, 0x3, 0x75, 0xCC, 0x80, - 0x3, 0x6E, 0xCC, 0xA3, 0x3, 0xE5, 0x86, 0xA4, 0x3, 0x47, 0xCC, 0x8C, 0x3, 0xE6, 0xB7, 0xB9, 0x4, - 0xCE, 0xB1, 0xCC, 0x94, 0x4, 0xD0, 0xAB, 0xCC, 0x88, 0x3, 0x69, 0xCC, 0x86, 0x5, 0xE2, 0x8A, 0xA8, - 0xCC, 0xB8, 0x3, 0x4D, 0xCC, 0xA3, 0x3, 0x79, 0xCC, 0x8A, 0x5, 0x6F, 0xCC, 0x83, 0xCC, 0x88, 0x3, - 0x48, 0xCC, 0x88, 0x4, 0xD1, 0x8D, 0xCC, 0x88, 0x4, 0xF0, 0xA7, 0x99, 0xA7, 0x3, 0xE5, 0xBA, 0xB3, - 0x5, 0xE2, 0x8A, 0xB4, 0xCC, 0xB8, 0x3, 0x53, 0xCC, 0xA3, 0x5, 0x65, 0xCC, 0x82, 0xCC, 0x83, 0x3, - 0xE5, 0xA3, 0xAE, 0x3, 0xE7, 0xA5, 0x9E, 0x1, 0x4B, 0x6, 0xE3, 0x81, 0x91, 0xE3, 0x82, 0x99, 0x6, - 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0x3, 0x53, 0xCC, 0x87, 0x3, 0xE6, 0xBF, 0x86, 0x3, 0xE9, 0x9A, - 0xA3, 0x6, 0xE0, 0xB1, 0x86, 0xE0, 0xB1, 0x96, 0x3, 0xE6, 0x95, 0x96, 0x8, 0xCE, 0xA9, 0xCC, 0x94, - 0xCC, 0x81, 0xCD, 0x85, 0x3, 0xE9, 0xB5, 0xA7, 0x3, 0xE5, 0xA7, 0xAC, 0x3, 0xE5, 0x85, 0x8D, 0x3, - 0x4E, 0xCC, 0x83, 0x5, 0x61, 0xCC, 0x87, 0xCC, 0x84, 0x3, 0xE6, 0xBB, 0x91, 0x3, 0xE7, 0x88, 0x90, - 0x3, 0xE8, 0x8F, 0x8A, 0x4, 0xCE, 0x99, 0xCC, 0x88, 0xC, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, - 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0x6, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0x3, 0xE9, 0xBC, 0x96, 0x3, - 0xE8, 0x8F, 0xAF, 0x3, 0x77, 0xCC, 0x80, 0x6, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0x4, 0xF0, 0xA6, - 0x88, 0xA8, 0x4, 0xD7, 0x90, 0xD6, 0xBC, 0x5, 0x45, 0xCC, 0x82, 0xCC, 0x81, 0x3, 0xE7, 0xA8, 0x9C, - 0x3, 0x64, 0xCC, 0x8C, 0x4, 0xCE, 0x9F, 0xCC, 0x93, 0x3, 0xE7, 0x97, 0xA2, 0x3, 0xE6, 0xA2, 0xA8, - 0x5, 0x41, 0xCC, 0x87, 0xCC, 0x84, 0x4, 0xD0, 0x97, 0xCC, 0x88, 0x6, 0xE3, 0x81, 0x99, 0xE3, 0x82, - 0x99, 0x5, 0x61, 0xCC, 0x8A, 0xCC, 0x81, 0x3, 0xE6, 0x9A, 0x88, 0x3, 0xE6, 0x83, 0x98, 0x4, 0xCE, - 0xA5, 0xCC, 0x80, 0x4, 0xF0, 0xA0, 0xA3, 0x9E, 0x4, 0xD7, 0xAA, 0xD6, 0xBC, 0x6, 0xCE, 0x95, 0xCC, - 0x94, 0xCC, 0x80, 0x3, 0xE6, 0xB6, 0x85, 0x4, 0xF0, 0xA7, 0x8F, 0x8A, 0x6, 0xE1, 0xAC, 0xBE, 0xE1, - 0xAC, 0xB5, 0x3, 0xE6, 0x82, 0x81, 0x3, 0xE9, 0xB6, 0xB4, 0x3, 0xE5, 0x8F, 0x9F, 0x3, 0xE5, 0x86, - 0x80, 0x3, 0xE5, 0x91, 0x88, 0x3, 0x69, 0xCC, 0xA3, 0x5, 0x4F, 0xCC, 0xA3, 0xCC, 0x82, 0x3, 0xE5, - 0xA8, 0xA7, 0x3, 0x44, 0xCC, 0xAD, 0x3, 0xE6, 0x91, 0xA9, 0x3, 0xE6, 0x89, 0x9D, 0x5, 0x4F, 0xCC, - 0x9B, 0xCC, 0xA3, 0x3, 0x45, 0xCC, 0x80, 0x4, 0xF0, 0xA4, 0xA0, 0x94, 0x1, 0x3B, 0x3, 0x54, 0xCC, - 0xAD, 0x5, 0xE2, 0x89, 0x8D, 0xCC, 0xB8, 0x6, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82, 0x3, 0xE6, 0x86, - 0x90, 0x3, 0x74, 0xCC, 0xA6, 0x3, 0xE9, 0xAC, 0x92, 0x4, 0xF0, 0xA0, 0x94, 0xA5, 0x3, 0xE7, 0xA2, - 0x91, 0x6, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80, 0x4, 0xD1, 0x96, 0xCC, 0x88, 0x3, 0xE7, 0xA1, 0xAB, - 0x6, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x9A, 0x3, 0x42, 0xCC, 0x87, 0x5, 0x55, 0xCC, 0x88, 0xCC, 0x80, - 0x3, 0xE5, 0xA9, 0xA6, 0x4, 0xF0, 0xA5, 0x98, 0xA6, 0x3, 0xE9, 0x83, 0xB1, 0x3, 0xE5, 0x99, 0xB4, - 0x3, 0xE7, 0xA6, 0x8F, 0x3, 0xE7, 0x8E, 0xA5, 0x4, 0xCE, 0xB1, 0xCC, 0x81, 0x3, 0xE5, 0x8C, 0x85, - 0x3, 0xE8, 0xBC, 0xAA, 0x3, 0xE7, 0x91, 0xA9, 0x6, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x9A, 0x3, 0xE5, - 0x8D, 0xB5, 0x6, 0xE0, 0xA8, 0x9C, 0xE0, 0xA8, 0xBC, 0x6, 0xCE, 0xB1, 0xCC, 0x81, 0xCD, 0x85, 0x3, - 0x47, 0xCC, 0x86, 0x4, 0xD1, 0x83, 0xCC, 0x8B, 0x3, 0x52, 0xCC, 0x91, 0x3, 0xE9, 0xBB, 0xBE, 0x5, - 0xE2, 0x86, 0x92, 0xCC, 0xB8, 0x4, 0xCE, 0xB5, 0xCC, 0x80, 0x3, 0xE7, 0x8F, 0x9E, 0x3, 0xE5, 0x81, - 0xBA, 0x4, 0xF0, 0xAA, 0x98, 0x80, 0x4, 0xCE, 0x97, 0xCC, 0x80, 0x6, 0xCF, 0x85, 0xCC, 0x88, 0xCC, - 0x81, 0x6, 0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x80, 0x3, 0xE8, 0x8E, 0xBD, 0x4, 0xCA, 0x92, 0xCC, 0x8C, - 0x4, 0xD1, 0x83, 0xCC, 0x84, 0x6, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0x3, 0x79, 0xCC, 0x80, 0x3, - 0xE6, 0xAE, 0xBB, 0x3, 0x75, 0xCC, 0x82, 0x6, 0xE3, 0x81, 0x8F, 0xE3, 0x82, 0x99, 0x5, 0xE2, 0x88, - 0x83, 0xCC, 0xB8, 0x3, 0x54, 0xCC, 0xA6, 0x3, 0xE5, 0x9F, 0xB4, 0x3, 0xE5, 0xAC, 0x88, 0x1, 0x60, - 0x6, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x99, 0x6, 0xD7, 0xA9, 0xD6, 0xBC, 0xD7, 0x82, 0x4, 0xF0, 0xA3, - 0xAB, 0xBA, 0x3, 0xE5, 0x90, 0x9D, 0x3, 0xE5, 0xBB, 0x92, 0x3, 0xE6, 0x9B, 0x86, 0x3, 0x61, 0xCC, - 0x8F, 0x3, 0xE6, 0x8F, 0x85, 0x3, 0xE5, 0x96, 0x84, 0x4, 0xCF, 0x89, 0xCD, 0x82, 0x3, 0xE4, 0x90, - 0x8B, 0x5, 0x41, 0xCC, 0x88, 0xCC, 0x84, 0x3, 0xE6, 0xB4, 0xBE, 0x6, 0xCF, 0x89, 0xCC, 0x93, 0xCD, - 0x82, 0x3, 0xE6, 0x88, 0x90, 0x4, 0xCE, 0x97, 0xCC, 0x93, 0x3, 0xE7, 0x92, 0x89, 0x4, 0xF0, 0xA3, - 0xA2, 0xA7, 0x3, 0xE6, 0x95, 0xB8, 0x3, 0xE8, 0x8A, 0x8B, 0x3, 0xE7, 0x8A, 0x80, 0x4, 0xD0, 0xB5, - 0xCC, 0x88, 0x3, 0xE8, 0x81, 0xB0, 0x3, 0x6C, 0xCC, 0xA3, 0x3, 0xE5, 0x8B, 0x89, 0x3, 0x49, 0xCC, - 0xB0, 0x3, 0x77, 0xCC, 0x8A, 0x3, 0x49, 0xCC, 0x83, 0x3, 0x45, 0xCC, 0x84, 0x3, 0x61, 0xCC, 0xA3, - 0x3, 0x57, 0xCC, 0x80, 0x3, 0xE8, 0x8C, 0x9D, 0x5, 0xE2, 0x88, 0xA5, 0xCC, 0xB8, 0x6, 0xE0, 0xBE, - 0xA1, 0xE0, 0xBE, 0xB7, 0x3, 0x55, 0xCC, 0x82, 0x5, 0x61, 0xCC, 0xA3, 0xCC, 0x86, 0x5, 0xE2, 0x8A, - 0x87, 0xCC, 0xB8, 0x3, 0xE9, 0x96, 0xAD, 0x3, 0xE5, 0x88, 0xBB, 0x3, 0x6F, 0xCC, 0x87, 0x4, 0xCF, - 0x85, 0xCC, 0x84, 0x3, 0xE6, 0xBA, 0xBA, 0x4, 0xF0, 0xA3, 0x8F, 0x95, 0x4, 0xD7, 0x91, 0xD6, 0xBC, - 0x4, 0xD0, 0xB6, 0xCC, 0x88, 0x4, 0xCE, 0xA5, 0xCC, 0x94, 0x5, 0xE2, 0x8A, 0xB3, 0xCC, 0xB8, 0x5, - 0x6F, 0xCC, 0x84, 0xCC, 0x80, 0x3, 0x6F, 0xCC, 0x88, 0x3, 0xE5, 0xA5, 0x88, 0x3, 0xE9, 0xA3, 0xAF, - 0x4, 0xD0, 0xB5, 0xCC, 0x86, 0x3, 0xE5, 0x9C, 0x96, 0x5, 0x61, 0xCC, 0x82, 0xCC, 0x89, 0x3, 0xE8, - 0xB4, 0x88, 0x3, 0xE7, 0xBE, 0x85, 0x5, 0x41, 0xCC, 0x86, 0xCC, 0x80, 0x3, 0xE3, 0x80, 0x88, 0x5, - 0xE2, 0x87, 0x90, 0xCC, 0xB8, 0x3, 0xE5, 0xBB, 0xBE, 0x5, 0x6F, 0xCC, 0x84, 0xCC, 0x81, 0x5, 0x6F, - 0xCC, 0x87, 0xCC, 0x84, 0x3, 0x75, 0xCC, 0xA8, 0x3, 0x59, 0xCC, 0x88, 0x6, 0xCF, 0x89, 0xCC, 0x93, - 0xCC, 0x81, 0x3, 0x41, 0xCC, 0x8A, 0x6, 0xCE, 0xB7, 0xCD, 0x82, 0xCD, 0x85, 0x6, 0xCE, 0x99, 0xCC, - 0x93, 0xCC, 0x81, 0x3, 0xE7, 0xAC, 0xA0, 0x3, 0xE5, 0xBB, 0xAC, 0x3, 0xE9, 0xB3, 0xBD, 0x3, 0xE7, - 0x8B, 0xBC, 0x3, 0xE3, 0xB4, 0xB3, 0x5, 0x65, 0xCC, 0xA7, 0xCC, 0x86, 0x3, 0xE7, 0x8A, 0x95, 0x3, - 0xE7, 0x89, 0x90, 0x3, 0xE3, 0x92, 0xB9, 0x3, 0x79, 0xCC, 0x87, 0x5, 0x4F, 0xCC, 0x88, 0xCC, 0x84, - 0x3, 0x49, 0xCC, 0x88, 0x3, 0xE9, 0xA4, 0xA9, 0x8, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, - 0x4, 0xCE, 0xBF, 0xCC, 0x94, 0x3, 0xE9, 0x9B, 0xA3, 0x4, 0xCE, 0xBF, 0xCC, 0x93, 0x6, 0xCE, 0x91, - 0xCC, 0x93, 0xCD, 0x85, 0x3, 0xE7, 0xB7, 0x87, 0x3, 0xE8, 0x9F, 0xA1, 0x4, 0xF0, 0xA0, 0x98, 0xBA, - 0x3, 0xE5, 0x99, 0x91, 0x3, 0xE8, 0xB3, 0x82, 0x3, 0x6C, 0xCC, 0x81, 0x3, 0x4F, 0xCC, 0x8F, 0x4, - 0xD0, 0x95, 0xCC, 0x80, 0x4, 0xD7, 0x90, 0xD6, 0xB7, 0x3, 0x4C, 0xCC, 0xB1, 0x4, 0xD7, 0x91, 0xD6, - 0xBF, 0x8, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0x6, 0xE0, 0xA4, 0xAB, 0xE0, 0xA4, - 0xBC, 0x6, 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99, 0x3, 0xE7, 0xA9, 0x8F, 0x3, 0xE6, 0x8D, 0x90, 0x3, - 0xE8, 0x9B, 0xA2, 0x8, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x3, 0xE5, 0x99, 0xA8, 0x3, - 0xE8, 0xA1, 0xA3, 0x3, 0x4E, 0xCC, 0xA3, 0x3, 0xE8, 0xAC, 0x81, 0x3, 0x72, 0xCC, 0x91, 0x4, 0xD7, - 0xA9, 0xD7, 0x81, 0x3, 0x74, 0xCC, 0xA3, 0x4, 0xF0, 0xA5, 0x89, 0x89, 0x3, 0x69, 0xCC, 0x80, 0x6, - 0xE3, 0x81, 0xA8, 0xE3, 0x82, 0x99, 0x3, 0x41, 0xCC, 0x80, 0x3, 0xE8, 0xAC, 0xB9, 0x3, 0xE5, 0x8F, - 0xAB, 0x3, 0xE9, 0xA9, 0xAA, 0x3, 0x68, 0xCC, 0x88, 0x3, 0x78, 0xCC, 0x88, 0x6, 0xE3, 0x83, 0x88, - 0xE3, 0x82, 0x99, 0x3, 0xE5, 0xB7, 0xA1, 0x6, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x80, 0x3, 0xE3, 0x9E, - 0x81, 0x4, 0xCE, 0x9F, 0xCC, 0x94, 0x6, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0x67, 0xCC, 0xA7, - 0x4, 0xD0, 0xB7, 0xCC, 0x88, 0x3, 0xE6, 0xAD, 0x94, 0x3, 0x43, 0xCC, 0x87, 0x3, 0x4C, 0xCC, 0xA7, - 0x6, 0xE3, 0x83, 0x84, 0xE3, 0x82, 0x99, 0x3, 0xE6, 0x85, 0x8C, 0x5, 0x45, 0xCC, 0x82, 0xCC, 0x80, - 0x4, 0xD7, 0xA6, 0xD6, 0xBC, 0x3, 0xE5, 0xB1, 0xA0, 0x6, 0xE0, 0xBE, 0x92, 0xE0, 0xBE, 0xB7, 0x3, - 0xE5, 0xBF, 0x8D, 0x4, 0xF0, 0xA0, 0xAD, 0xA3, 0x3, 0x6E, 0xCC, 0x87, 0x4, 0xC3, 0xA6, 0xCC, 0x81, - 0x6, 0xE0, 0xAC, 0xA2, 0xE0, 0xAC, 0xBC, 0x4, 0xD0, 0xBA, 0xCC, 0x81, 0x3, 0xE6, 0xBB, 0x87, 0x5, - 0xE2, 0x86, 0x90, 0xCC, 0xB8, 0x4, 0xCE, 0xB7, 0xCD, 0x85, 0x3, 0x65, 0xCC, 0x8F, 0x5, 0xE2, 0x86, - 0x94, 0xCC, 0xB8, 0x3, 0xE5, 0xAF, 0xBF, 0x3, 0x55, 0xCC, 0x83, 0x3, 0x79, 0xCC, 0x88, 0xC, 0xF0, - 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0x3, 0xE7, 0xB3, 0xA8, 0x4, - 0xF0, 0xA8, 0xAF, 0xBA, 0x3, 0xE5, 0xB9, 0xA9, 0x3, 0x75, 0xCC, 0x84, 0x3, 0xE7, 0xA5, 0x96, 0x3, - 0x6C, 0xCC, 0xA7, 0x5, 0x6C, 0xCC, 0xA3, 0xCC, 0x84, 0x3, 0x45, 0xCC, 0x81, 0x3, 0x74, 0xCC, 0x87, - 0x3, 0xE6, 0xBB, 0x8B, 0x4, 0xCE, 0x97, 0xCC, 0x81, 0x3, 0x6F, 0xCC, 0x8C, 0x3, 0xE7, 0x9B, 0xA7, - 0x3, 0x77, 0xCC, 0xA3, 0x3, 0xE6, 0x90, 0xA2, 0x8, 0xF0, 0x91, 0x84, 0xB1, 0xF0, 0x91, 0x84, 0xA7, - 0x6, 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99, 0x3, 0x56, 0xCC, 0x83, 0x3, 0x55, 0xCC, 0x86, 0x5, 0xE2, - 0x8A, 0x91, 0xCC, 0xB8, 0x8, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x6, 0xCE, 0xB7, - 0xCC, 0x94, 0xCD, 0x85, 0x4, 0xF0, 0xA5, 0x9B, 0x85, 0x3, 0x59, 0xCC, 0xA3, 0x3, 0x67, 0xCC, 0x8C, - 0x3, 0x65, 0xCC, 0xA8, 0x3, 0xE5, 0xB1, 0xA4, 0x3, 0xE8, 0x8A, 0xB3, 0x6, 0xE3, 0x83, 0x86, 0xE3, - 0x82, 0x99, 0x3, 0xE6, 0x87, 0x9E, 0x6, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85, 0x3, 0xE4, 0xB3, 0xAD, - 0x8, 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x3, 0x41, 0xCC, 0x82, 0x3, 0xE4, 0xB8, 0xA6, - 0x4, 0xF0, 0xA5, 0xAE, 0xAB, 0x6, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x9A, 0x3, 0xE9, 0x81, 0xBC, 0x3, - 0xE5, 0x98, 0x86, 0x4, 0xCF, 0x85, 0xCC, 0x80, 0x4, 0xD7, 0xA0, 0xD6, 0xBC, 0x3, 0xE7, 0xA5, 0x88, - 0x3, 0x4F, 0xCC, 0x81, 0x3, 0xE4, 0xAF, 0x8E, 0x3, 0xE5, 0xA9, 0xA2, 0x3, 0xE5, 0xBA, 0xA6, 0x3, - 0xE7, 0x80, 0xB9, 0x6, 0xE1, 0xAC, 0x87, 0xE1, 0xAC, 0xB5, 0x3, 0xE6, 0x80, 0x92, 0x3, 0xE6, 0x9D, - 0x96, 0x3, 0xE5, 0xA2, 0xAC, 0x3, 0x61, 0xCC, 0x8C, 0x3, 0x49, 0xCC, 0x80, 0x3, 0x75, 0xCC, 0xA4, - 0x3, 0xE7, 0xB1, 0xA0, 0x4, 0xF0, 0xA6, 0x96, 0xA8, 0x4, 0xCE, 0x99, 0xCC, 0x84, 0x4, 0xF0, 0xA2, - 0x86, 0x83, 0x3, 0xE7, 0x88, 0xB5, 0x3, 0xE5, 0x8C, 0x97, 0x6, 0xE3, 0x83, 0xAF, 0xE3, 0x82, 0x99, - 0x3, 0xE6, 0xAC, 0x84, 0x3, 0xE5, 0x86, 0xAC, 0x3, 0xE5, 0x80, 0x82, 0x3, 0xE7, 0xB4, 0xAF, 0x3, - 0x75, 0xCC, 0x91, 0x3, 0xE6, 0xAC, 0xA1, 0x3, 0xE7, 0xAF, 0x80, 0x3, 0xE9, 0x86, 0xB4, 0x3, 0xE5, - 0xA1, 0x9A, 0x3, 0xE9, 0xA0, 0x98, 0x5, 0xE2, 0x88, 0x88, 0xCC, 0xB8, 0x5, 0x6F, 0xCC, 0xA3, 0xCC, - 0x82, 0x6, 0xD7, 0xA9, 0xD6, 0xBC, 0xD7, 0x81, 0x4, 0xCF, 0x85, 0xCD, 0x82, 0x4, 0xF0, 0xAA, 0x88, - 0x8E, 0x5, 0x45, 0xCC, 0x82, 0xCC, 0x83, 0x6, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0x5, 0x75, 0xCC, - 0x9B, 0xCC, 0x89, 0x3, 0xE7, 0xAA, 0xB1, 0x4, 0xCE, 0xB1, 0xCC, 0x84, 0x3, 0xE6, 0x97, 0xA2, 0x3, - 0xE8, 0xA0, 0x9F, 0xC, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB2, - 0x4, 0xCE, 0xA9, 0xCC, 0x80, 0x3, 0xE4, 0xBA, 0x86, 0x6, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x81, 0x4, - 0xF0, 0xA3, 0xBE, 0x8E, 0x6, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x85, 0x3, 0x65, 0xCC, 0x80, 0x8, 0xCF, - 0x89, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x5, 0xE2, 0x89, 0x85, 0xCC, 0xB8, 0x4, 0xF0, 0xA7, - 0xBB, 0x93, 0x3, 0x6E, 0xCC, 0xB1, 0x3, 0xE8, 0x87, 0xA8, 0x5, 0xE2, 0x89, 0x88, 0xCC, 0xB8, 0x3, - 0x62, 0xCC, 0xB1, 0x5, 0xE2, 0x8A, 0x82, 0xCC, 0xB8, 0x6, 0xCE, 0xB9, 0xCC, 0x94, 0xCD, 0x82, 0x3, - 0xE7, 0xA6, 0x8D, 0x3, 0x77, 0xCC, 0x88, 0x3, 0x6E, 0xCC, 0xAD, 0x3, 0xE8, 0xBC, 0xB8, 0x3, 0x44, - 0xCC, 0xB1, 0x3, 0xE5, 0x89, 0x86, 0x4, 0xF0, 0xA5, 0x84, 0x99, 0x3, 0xE7, 0x92, 0x85, 0x3, 0xE7, - 0xA7, 0xAB, 0x4, 0xF0, 0xA6, 0x93, 0x9A, 0x3, 0xE7, 0xA9, 0x80, 0x5, 0x41, 0xCC, 0x82, 0xCC, 0x83, - 0x3, 0xE6, 0xBC, 0xA2, 0x5, 0x4F, 0xCC, 0x83, 0xCC, 0x84, 0x3, 0xE3, 0xA3, 0x87, 0x6, 0xE0, 0xBD, - 0xB1, 0xE0, 0xBD, 0xB4, 0x3, 0x6B, 0xCC, 0xA7, 0x3, 0x72, 0xCC, 0x87, 0x4, 0xF0, 0xA5, 0xB3, 0x90, - 0x6, 0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99, 0x4, 0xD0, 0x96, 0xCC, 0x88, 0x3, 0x55, 0xCC, 0x8A, 0x3, - 0xE8, 0x82, 0xB2, 0x3, 0x61, 0xCC, 0xA5, 0x4, 0xCF, 0x92, 0xCC, 0x88, 0x3, 0xE6, 0x98, 0x93, 0x3, - 0x74, 0xCC, 0xB1, 0x6, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0xE5, 0xB8, 0xA8, 0x8, 0xCE, 0xA9, - 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x3, 0xE5, 0xBF, 0xB5, 0x3, 0x6F, 0xCC, 0x86, 0x3, 0xE5, 0x83, - 0xA7, 0x3, 0xE4, 0x9A, 0xBE, 0x3, 0xE7, 0x8B, 0x80, 0x5, 0x6F, 0xCC, 0x9B, 0xCC, 0x89, 0x4, 0xF0, - 0xA3, 0xAA, 0x8D, 0x3, 0xE6, 0xBC, 0xA3, 0x3, 0x41, 0xCC, 0xA3, 0x3, 0x65, 0xCC, 0xB0, 0x3, 0xE7, - 0xA5, 0xA5, 0x8, 0xF0, 0x91, 0x82, 0x9B, 0xF0, 0x91, 0x82, 0xBA, 0x3, 0x59, 0xCC, 0x89, 0x3, 0xE5, - 0x8A, 0xA3, 0x8, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE6, 0x85, 0x84, 0x4, 0xD0, - 0xA7, 0xCC, 0x88, 0x3, 0x4F, 0xCC, 0xA3, 0x4, 0xD0, 0xB8, 0xCC, 0x88, 0x3, 0x6B, 0xCC, 0x8C, 0x5, - 0x45, 0xCC, 0x84, 0xCC, 0x81, 0x3, 0xE4, 0x82, 0x96, 0x3, 0xE6, 0x9A, 0xB4, 0x4, 0xF0, 0xAA, 0x8E, - 0x92, 0x3, 0xE9, 0x99, 0xB5, 0x6, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x81, 0x4, 0xD3, 0x99, 0xCC, 0x88, - 0x3, 0xE8, 0x84, 0x83, 0x3, 0xE9, 0xB8, 0x9E, 0x3, 0x75, 0xCC, 0x89, 0x5, 0xE1, 0xBE, 0xBF, 0xCD, - 0x82, 0x3, 0xE6, 0x85, 0x8E, 0x4, 0xF0, 0xA4, 0x98, 0x88, 0x3, 0x61, 0xCC, 0x82, 0x3, 0xE8, 0xA0, - 0x81, 0x4, 0xF0, 0xA1, 0xA7, 0x88, 0x3, 0x5A, 0xCC, 0x81, 0x5, 0xE2, 0x87, 0x94, 0xCC, 0xB8, 0x4, - 0xC3, 0x86, 0xCC, 0x84, 0x6, 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0x6, 0xE3, 0x82, 0xB5, 0xE3, - 0x82, 0x99, 0x3, 0xE7, 0xA1, 0x8E, 0x3, 0x65, 0xCC, 0x82, 0x6, 0xE3, 0x81, 0x8B, 0xE3, 0x82, 0x99, - 0x6, 0xE1, 0xAC, 0xBA, 0xE1, 0xAC, 0xB5, 0x3, 0xE4, 0xB3, 0xB8, 0x4, 0xD0, 0xB6, 0xCC, 0x86, 0x3, - 0xE4, 0xB8, 0xBD, 0x3, 0x72, 0xCC, 0xA3, 0x5, 0xE2, 0x8A, 0x83, 0xCC, 0xB8, 0x3, 0xE7, 0x83, 0x88, - 0x3, 0xE7, 0x98, 0x9D, 0x3, 0x61, 0xCC, 0x89, 0x5, 0x75, 0xCC, 0x9B, 0xCC, 0xA3, 0x3, 0xE3, 0x9B, - 0xBC, 0x3, 0xE4, 0xB9, 0x81, 0x6, 0xE0, 0xA8, 0x96, 0xE0, 0xA8, 0xBC, 0x3, 0x48, 0xCC, 0x8C, 0x3, - 0x57, 0xCC, 0x82, 0x3, 0x6D, 0xCC, 0x87, 0x3, 0xE5, 0xBE, 0x9A, 0x3, 0xE4, 0x8C, 0x81, 0x3, 0xE9, - 0xBD, 0x83, 0x4, 0xCE, 0xA1, 0xCC, 0x94, 0x3, 0xE5, 0x85, 0x85, 0x4, 0xF0, 0xA5, 0x83, 0xB3, 0x3, - 0x45, 0xCC, 0xB0, 0x4, 0xCF, 0x89, 0xCD, 0x85, 0x6, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x80, 0x3, 0xE6, - 0x8B, 0xBE, 0x3, 0xE5, 0x95, 0x93, 0x3, 0xE7, 0x8D, 0xBA, 0x3, 0x49, 0xCC, 0x8F, 0x3, 0xE3, 0xAC, - 0x88, 0x3, 0x55, 0xCC, 0xA4, 0x3, 0xE8, 0xB3, 0x81, 0x4, 0xCE, 0x99, 0xCC, 0x80, 0x3, 0xE6, 0x92, - 0x9D, 0x3, 0xE8, 0x88, 0x81, 0x3, 0xE6, 0xA2, 0x8E, 0x3, 0xE8, 0x9C, 0xA8, 0x4, 0xD0, 0x86, 0xCC, - 0x88, 0x4, 0xCE, 0xB9, 0xCC, 0x94, 0x6, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x99, 0x5, 0xE2, 0x8A, 0x92, - 0xCC, 0xB8, 0x3, 0xE5, 0xA5, 0xA2, 0x3, 0xE6, 0x8B, 0x94, 0x3, 0xE5, 0x8B, 0x92, 0x3, 0xE6, 0xAD, - 0xB9, 0x3, 0x52, 0xCC, 0x81, 0x4, 0xD7, 0x9E, 0xD6, 0xBC, 0x3, 0xE5, 0x88, 0x97, 0x4, 0xD8, 0xA7, - 0xD9, 0x94, 0x3, 0xE5, 0x97, 0x80, 0x3, 0x61, 0xCC, 0x91, 0x3, 0xE7, 0xBC, 0xBE, 0x4, 0xF0, 0xA3, - 0x8D, 0x9F, 0x3, 0x67, 0xCC, 0x87, 0x3, 0x68, 0xCC, 0xB1, 0x3, 0xE8, 0xA3, 0x8F, 0x3, 0xE5, 0xBD, - 0xAB, 0x5, 0xE2, 0x88, 0xA3, 0xCC, 0xB8, 0x6, 0xE0, 0xA8, 0x97, 0xE0, 0xA8, 0xBC, 0x3, 0x57, 0xCC, - 0x81, 0x3, 0xE6, 0xB7, 0x9A, 0x3, 0x4F, 0xCC, 0x8B, 0x3, 0xE3, 0xA0, 0xAF, 0x3, 0xE6, 0x81, 0xB5, - 0x4, 0xCE, 0xB9, 0xCC, 0x88, 0x3, 0x53, 0xCC, 0x82, 0x3, 0xE3, 0xA3, 0xA3, 0x3, 0x6E, 0xCC, 0x8C, - 0x6, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x80, 0x3, 0xE9, 0x9A, 0xB8, 0x4, 0xD7, 0x93, 0xD6, 0xBC, 0x2, - 0xCA, 0xB9, 0x3, 0xE5, 0xBF, 0xB9, 0x6, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99, 0x4, 0xCE, 0x99, 0xCC, - 0x81, 0x3, 0x57, 0xCC, 0x88, 0x6, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80, 0x6, 0xCE, 0x95, 0xCC, 0x94, - 0xCC, 0x81, 0x3, 0x64, 0xCC, 0xB1, 0x6, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82, 0x3, 0xE6, 0x91, 0xB7, - 0x5, 0x6F, 0xCC, 0x83, 0xCC, 0x84, 0x3, 0xE5, 0x9E, 0x8B, 0x3, 0xE9, 0xB1, 0x80, 0x3, 0xE6, 0x8A, - 0xB1, 0x3, 0xE6, 0x86, 0xAF, 0x6, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x3, 0xE6, 0x9F, 0xBA, 0x3, - 0xE5, 0x85, 0x80, 0x3, 0xE5, 0x9C, 0x97, 0x5, 0x41, 0xCC, 0x86, 0xCC, 0x81, 0x6, 0xE0, 0xB3, 0x86, - 0xE0, 0xB3, 0x96, 0x3, 0xE6, 0x9B, 0xB8, 0x3, 0xE3, 0xB6, 0x96, 0x3, 0xE7, 0x90, 0x86, 0x3, 0xE7, - 0x94, 0x86, 0x4, 0xD7, 0xA4, 0xD6, 0xBF, 0x3, 0xE7, 0x81, 0xB7, 0x3, 0xE5, 0xA3, 0x98, 0x3, 0xE6, - 0xAD, 0xB2, 0x6, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x80, 0x3, 0x68, 0xCC, 0xA7, 0x6, 0xCE, 0x91, 0xCC, - 0x93, 0xCC, 0x80, 0x3, 0x7A, 0xCC, 0x8C, 0x3, 0xE5, 0xA2, 0xA8, 0x6, 0xCE, 0xB9, 0xCC, 0x93, 0xCD, - 0x82, 0x3, 0xE3, 0xA1, 0xBC, 0x3, 0xE6, 0x88, 0x80, 0x3, 0xE6, 0xB7, 0xAA, 0x6, 0xE3, 0x81, 0xBB, - 0xE3, 0x82, 0x99, 0x6, 0xCF, 0x89, 0xCC, 0x81, 0xCD, 0x85, 0x6, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, - 0x81, 0x3, 0x4F, 0xCC, 0x82, 0x3, 0xE7, 0xAB, 0xAE, 0x5, 0x4C, 0xCC, 0xA3, 0xCC, 0x84, 0x4, 0xD7, - 0xA9, 0xD7, 0x82, 0x3, 0xE7, 0x9E, 0x8B, 0x3, 0x48, 0xCC, 0xA7, 0x3, 0xE7, 0xB4, 0x80, 0x3, 0x3E, - 0xCC, 0xB8, 0x4, 0xCF, 0x85, 0xCC, 0x88, 0x5, 0x4F, 0xCC, 0x82, 0xCC, 0x83, 0x4, 0xCE, 0x91, 0xCC, - 0x94, 0x3, 0xE4, 0xB8, 0x8D, 0x3, 0xE8, 0xA3, 0x97, 0x3, 0x68, 0xCC, 0x87, 0x6, 0xCF, 0x85, 0xCC, - 0x93, 0xCC, 0x80, 0x6, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC, 0x3, 0xE5, 0xA2, 0xB3, 0x5, 0x41, 0xCC, - 0x8A, 0xCC, 0x81, 0x3, 0xE6, 0xA8, 0x82, 0x3, 0xE8, 0x87, 0x98, 0x6, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, - 0x81, 0x3, 0xE6, 0xA6, 0xA3, 0x8, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0x3, 0xE8, 0x97, - 0xBA, 0x5, 0x75, 0xCC, 0x83, 0xCC, 0x81, 0x5, 0x75, 0xCC, 0x88, 0xCC, 0x84, 0x3, 0xE5, 0x90, 0x86, - 0x4, 0xCC, 0x88, 0xCC, 0x81, 0x4, 0xF0, 0xA5, 0xBE, 0x86, 0x3, 0xE7, 0x82, 0x99, 0x3, 0xE7, 0xB3, - 0x96, 0x3, 0xE8, 0xB3, 0x93, 0x3, 0xE7, 0xAA, 0x81, 0x3, 0x4C, 0xCC, 0xAD, 0x3, 0x72, 0xCC, 0x8C, - 0x3, 0x4D, 0xCC, 0x87, 0x3, 0x41, 0xCC, 0x83, 0x6, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x81, 0x3, 0x6F, - 0xCC, 0xA8, 0x4, 0xF0, 0xA3, 0x80, 0x8A, 0x3, 0x6E, 0xCC, 0xA7, 0x8, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, - 0x81, 0xCD, 0x85, 0x4, 0xD0, 0x90, 0xCC, 0x88, 0x3, 0xE5, 0x9B, 0xB9, 0x3, 0xE6, 0x86, 0xA4, 0x3, - 0xE9, 0x80, 0xA3, 0x3, 0xE6, 0x9D, 0x8E, 0x3, 0xE6, 0x85, 0x88, 0x3, 0x55, 0xCC, 0x8B, 0x3, 0xE8, - 0x81, 0x86, 0x3, 0xE5, 0xB6, 0xBA, 0x6, 0xE3, 0x82, 0xB3, 0xE3, 0x82, 0x99, 0x3, 0xE8, 0x98, 0x86, - 0x5, 0xE2, 0x89, 0xBC, 0xCC, 0xB8, 0x5, 0xE2, 0x87, 0x92, 0xCC, 0xB8, 0x4, 0xF0, 0xA6, 0xAC, 0xBC, - 0x3, 0xE5, 0x89, 0xB7, 0x6, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0x3, 0x44, 0xCC, 0xA3, 0x8, 0xCE, - 0x91, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x3, 0xE8, 0x93, 0xB3, 0x3, 0xE8, 0xBE, 0x9E, 0x3, 0x49, - 0xCC, 0x84, 0x6, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x81, 0x4, 0xD7, 0x94, 0xD6, 0xBC, 0x5, 0x55, 0xCC, - 0x84, 0xCC, 0x88, 0x4, 0xD7, 0xA3, 0xD6, 0xBC, 0x3, 0xE8, 0xAB, 0xBE, 0x3, 0xE7, 0xBE, 0x95, 0x3, - 0x54, 0xCC, 0x87, 0x3, 0xE9, 0x9F, 0x9B, 0x5, 0xE2, 0x8A, 0xB2, 0xCC, 0xB8, 0x3, 0x72, 0xCC, 0xA7, - 0x5, 0x45, 0xCC, 0x84, 0xCC, 0x80, 0x3, 0x4E, 0xCC, 0xB1, 0x3, 0xE3, 0x80, 0x89, 0x3, 0xE6, 0x85, - 0xA0, 0x6, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85, 0x5, 0xE1, 0xBF, 0xBE, 0xCD, 0x82, 0x5, 0x61, 0xCC, - 0x86, 0xCC, 0x80, 0x4, 0xD7, 0x95, 0xD6, 0xBC, 0x3, 0xE6, 0xB5, 0xA9, 0x3, 0xE8, 0x8F, 0xB1, 0x4, - 0xF0, 0xA5, 0x81, 0x84, 0x3, 0x59, 0xCC, 0x84, 0x3, 0xE8, 0x8E, 0xAD, 0x8, 0xF0, 0x91, 0x92, 0xB9, - 0xF0, 0x91, 0x92, 0xB0, 0x6, 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82, 0x3, 0x63, 0xCC, 0x82, 0x3, 0xE5, - 0xAE, 0x85, 0x3, 0xE5, 0xBB, 0x89, 0x3, 0xE9, 0xBE, 0x8D, 0x3, 0x73, 0xCC, 0x87, 0x5, 0xE2, 0x8A, - 0x86, 0xCC, 0xB8, 0x3, 0xE5, 0xA5, 0x84, 0x5, 0x6F, 0xCC, 0x82, 0xCC, 0x81, 0xC, 0xF0, 0x9D, 0x85, - 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB0, 0x3, 0xE6, 0xB5, 0xB8, 0x3, 0xE8, 0x9A, - 0xA9, 0x3, 0xE7, 0x92, 0x98, 0x3, 0xE5, 0x97, 0x82, 0x6, 0xE0, 0xAD, 0x87, 0xE0, 0xAD, 0x97, 0x3, - 0xE6, 0x99, 0x89, 0x4, 0xCE, 0xB9, 0xCC, 0x86, 0x3, 0xE6, 0xAB, 0x9B, 0x6, 0xE0, 0xAD, 0x87, 0xE0, - 0xAD, 0x96, 0x3, 0xE7, 0xB3, 0xA7, 0x5, 0x69, 0xCC, 0x88, 0xCC, 0x81, 0x3, 0x4C, 0xCC, 0xA3, 0x4, - 0xD0, 0xB8, 0xCC, 0x80, 0x4, 0xD1, 0x83, 0xCC, 0x86, 0x5, 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0x4, 0xF0, - 0xA6, 0xBE, 0xB1, 0x3, 0x67, 0xCC, 0x81, 0x3, 0xE6, 0x80, 0x9C, 0x3, 0xE9, 0xBC, 0xBB, 0x3, 0xE8, - 0x98, 0xBF, 0x4, 0xD0, 0x98, 0xCC, 0x86, 0x3, 0x49, 0xCC, 0xA3, 0x6, 0xE0, 0xA8, 0xAB, 0xE0, 0xA8, - 0xBC, 0x3, 0x41, 0xCC, 0x84, 0x6, 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0x99, 0x4, 0xCE, 0xB7, 0xCC, 0x80, - 0x3, 0x55, 0xCC, 0xA8, 0x6, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x81, 0x3, 0xE5, 0xA4, 0x86, 0x3, 0xE3, - 0xAB, 0xA4, 0x3, 0xE7, 0x99, 0x82, 0x3, 0xE5, 0x8D, 0x9A, 0x4, 0xCE, 0xB9, 0xCC, 0x93, 0x3, 0xE5, - 0x92, 0xA2, 0x5, 0x65, 0xCC, 0x82, 0xCC, 0x81, 0x3, 0xE6, 0x85, 0xBA, 0x4, 0xF0, 0xA1, 0x9B, 0xAA, - 0x4, 0xCE, 0x95, 0xCC, 0x93, 0x4, 0xC6, 0xB7, 0xCC, 0x8C, 0x3, 0x4D, 0xCC, 0x81, 0x4, 0xD0, 0x90, - 0xCC, 0x86, 0x5, 0x75, 0xCC, 0x9B, 0xCC, 0x81, 0x4, 0xF0, 0xA4, 0xB2, 0x92, 0x3, 0x55, 0xCC, 0x8C, - 0x3, 0xE5, 0x8B, 0x9E, 0x3, 0xE9, 0xA3, 0xBC, 0x3, 0xE3, 0xAD, 0x89, 0x3, 0xE7, 0xA4, 0xBC, 0x3, - 0xE8, 0xAD, 0x98, 0x3, 0x45, 0xCC, 0xA3, 0x4, 0xCE, 0xB9, 0xCC, 0x80, 0x3, 0xE6, 0xB3, 0x8C, 0x5, - 0x55, 0xCC, 0x9B, 0xCC, 0x89, 0x6, 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0x99, 0x6, 0xE1, 0xAC, 0xBF, - 0xE1, 0xAC, 0xB5, 0x4, 0xF0, 0xA2, 0x9B, 0x94, 0x3, 0xE6, 0x9E, 0x85, 0x6, 0xE0, 0xA6, 0xA2, 0xE0, - 0xA6, 0xBC, 0x5, 0xE2, 0x89, 0xBA, 0xCC, 0xB8, 0x3, 0xE8, 0xAA, 0xBF, 0x3, 0xE8, 0xAB, 0x96, 0x3, - 0xE7, 0xB3, 0xA3, 0x5, 0x41, 0xCC, 0x82, 0xCC, 0x89, 0x6, 0xE0, 0xBE, 0x9C, 0xE0, 0xBE, 0xB7, 0x5, - 0x55, 0xCC, 0x83, 0xCC, 0x81, 0x6, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0x3, 0xE6, 0xBC, 0x8F, 0x4, - 0xF0, 0xA9, 0x90, 0x8A, 0x3, 0xE5, 0xBB, 0x93, 0x3, 0xE4, 0xBE, 0xBB, 0x5, 0x63, 0xCC, 0xA7, 0xCC, - 0x81, 0x3, 0xE7, 0x9C, 0x81, 0x3, 0xE7, 0xA5, 0x90, 0x3, 0x52, 0xCC, 0xB1, 0x6, 0xE3, 0x83, 0x92, - 0xE3, 0x82, 0x99, 0x5, 0xE2, 0x89, 0xA4, 0xCC, 0xB8, 0x3, 0xE6, 0x9C, 0xA1, 0x4, 0xCE, 0x91, 0xCC, - 0x86, 0x3, 0x64, 0xCC, 0x87, 0x3, 0xE7, 0xA5, 0xBF, 0x4, 0xCF, 0x85, 0xCC, 0x94, 0x4, 0xD7, 0xA4, - 0xD6, 0xBC, 0x3, 0xE5, 0x86, 0xB7, 0x3, 0xE4, 0x91, 0xAB, 0x8, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, - 0x85, 0xA5, 0x4, 0xF0, 0xA5, 0x83, 0xB2, 0x3, 0x6D, 0xCC, 0x81, 0x6, 0xE3, 0x83, 0x81, 0xE3, 0x82, - 0x99, 0x3, 0x4F, 0xCC, 0xA8, 0x4, 0xF0, 0xA9, 0x96, 0xB6, 0x3, 0x6C, 0xCC, 0xAD, 0x4, 0xD0, 0x95, - 0xCC, 0x86, 0x3, 0xE7, 0x91, 0x9C, 0x3, 0xE5, 0x8F, 0xA5, 0x3, 0xE7, 0x98, 0x90, 0x5, 0x55, 0xCC, - 0x88, 0xCC, 0x84, 0x3, 0xE6, 0xB8, 0xAF, 0x3, 0xE4, 0x80, 0x88, 0x3, 0x6F, 0xCC, 0x8B, 0x6, 0xCF, - 0x85, 0xCC, 0x94, 0xCD, 0x82, 0x3, 0x6D, 0xCC, 0xA3, 0x3, 0xE5, 0x91, 0x82, 0x4, 0xCE, 0xA9, 0xCC, - 0x94, 0x3, 0xE6, 0xA0, 0x97, 0x6, 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x80, 0x3, 0x45, 0xCC, 0x87, 0x3, - 0x54, 0xCC, 0xB1, 0x6, 0xE3, 0x83, 0xB0, 0xE3, 0x82, 0x99, 0x4, 0xF0, 0xA6, 0xB0, 0xB6, 0x5, 0xE1, - 0xBF, 0xBE, 0xCC, 0x80, 0x3, 0xE6, 0xA2, 0x81, 0x4, 0xF0, 0xA1, 0xB7, 0xA4, 0x5, 0xE2, 0x89, 0xBB, - 0xCC, 0xB8, 0x3, 0x64, 0xCC, 0xA7, 0x4, 0xD0, 0x9A, 0xCC, 0x81, 0x3, 0xE6, 0xAA, 0xA8, 0x3, 0x75, - 0xCC, 0x81, 0x3, 0x45, 0xCC, 0x8F, 0x6, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80, 0x3, 0x61, 0xCC, 0x81, - 0x6, 0xE1, 0xAC, 0xBC, 0xE1, 0xAC, 0xB5, 0x6, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0x3, 0xE8, 0x81, - 0xA0, 0x3, 0xE2, 0x80, 0x82, 0x4, 0xD7, 0xA9, 0xD6, 0xBC, 0x3, 0xE6, 0x9F, 0xB3, 0x3, 0xE5, 0xB7, - 0xBD, 0x3, 0xE7, 0x98, 0x9F, 0x5, 0xE2, 0x8A, 0xA2, 0xCC, 0xB8, 0x4, 0xD3, 0xA9, 0xCC, 0x88, 0x6, - 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x85, 0x3, 0xE3, 0xB1, 0x8E, 0x3, 0x59, 0xCC, 0x83, 0x3, 0xE5, 0x9F, - 0x8E, 0x3, 0xE4, 0x97, 0x97, 0x3, 0xE5, 0x90, 0x8F, 0x3, 0xE6, 0x87, 0xB2, 0x3, 0xE7, 0xAF, 0x86, - 0x3, 0xE8, 0x8B, 0xA6, 0xC, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, - 0xAF, 0x3, 0x4F, 0xCC, 0x9B, 0x3, 0x69, 0xCC, 0x81, 0x4, 0xD7, 0x9B, 0xD6, 0xBC, 0x8, 0xCE, 0xB7, - 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x3, 0xE4, 0x9B, 0x87, 0x3, 0xE4, 0x8F, 0x99, 0x5, 0xE2, 0x89, - 0xA5, 0xCC, 0xB8, 0x3, 0xE7, 0xB6, 0xBE, 0x3, 0xE8, 0x8F, 0x89, 0x5, 0x6F, 0xCC, 0x9B, 0xCC, 0x81, - 0x6, 0xCE, 0xB1, 0xCD, 0x82, 0xCD, 0x85, 0x3, 0xE5, 0x8D, 0xBF, 0x5, 0x61, 0xCC, 0x82, 0xCC, 0x83, - 0x3, 0x4E, 0xCC, 0xA7, 0x3, 0xE9, 0x8B, 0x97, 0x8, 0xF0, 0x91, 0x84, 0xB2, 0xF0, 0x91, 0x84, 0xA7, - 0x3, 0x6B, 0xCC, 0x81, 0x6, 0xCF, 0x89, 0xCD, 0x82, 0xCD, 0x85, 0x6, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, - 0x80, 0x4, 0xD0, 0xAD, 0xCC, 0x88, 0x3, 0x41, 0xCC, 0x8C, 0x6, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, - 0x3, 0xE8, 0x8F, 0xA7, 0x3, 0xE5, 0xBD, 0xA2, 0x3, 0x52, 0xCC, 0x8C, 0x5, 0x41, 0xCC, 0x86, 0xCC, - 0x83, 0x4, 0xD9, 0x8A, 0xD9, 0x94, 0x5, 0x4F, 0xCC, 0xA8, 0xCC, 0x84, 0x6, 0xCE, 0x97, 0xCC, 0x94, - 0xCC, 0x80, 0x3, 0xE5, 0x85, 0xA8, 0x4, 0xF0, 0xA3, 0xB2, 0xBC, 0x3, 0xE6, 0x9D, 0x93, 0x3, 0xE8, - 0xB5, 0xB7, 0x6, 0xE0, 0xA4, 0x96, 0xE0, 0xA4, 0xBC, 0x3, 0x49, 0xCC, 0x91, 0x4, 0xCE, 0xB7, 0xCC, - 0x93, 0x3, 0xE3, 0x93, 0x9F, 0x8, 0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92, 0xBD, 0x3, 0xE6, 0xB3, - 0x8D, 0x8, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x8, 0xF0, 0x91, 0xA4, 0xB5, 0xF0, - 0x91, 0xA4, 0xB0, 0x3, 0x52, 0xCC, 0xA3, 0x3, 0x55, 0xCC, 0x91, 0x4, 0xF0, 0xA6, 0x89, 0x87, 0x6, - 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0x5, 0x75, 0xCC, 0x88, 0xCC, 0x8C, 0x3, 0xE9, 0x99, 0xBC, 0x6, - 0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x80, 0x4, 0xF0, 0xAA, 0x84, 0x85, 0x3, 0x78, 0xCC, 0x87, 0x3, 0xE9, - 0xA7, 0x82, 0x3, 0xE6, 0x88, 0xB4, 0x3, 0xE6, 0x8D, 0xBB, 0x8, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, - 0xCD, 0x85, 0x4, 0xD0, 0x96, 0xCC, 0x86, 0x3, 0xE8, 0x8D, 0xA3, 0x6, 0xCE, 0x99, 0xCC, 0x93, 0xCC, - 0x80, 0x4, 0xF0, 0xA1, 0xB4, 0x8B, 0x6, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x81, 0x4, 0xCE, 0xBF, 0xCC, - 0x80, 0x6, 0xE0, 0xBE, 0x90, 0xE0, 0xBE, 0xB5, 0x3, 0x48, 0xCC, 0x87, 0x6, 0xCF, 0x89, 0xCC, 0x80, - 0xCD, 0x85, 0x3, 0xE7, 0xBF, 0xBA, 0x3, 0xE6, 0xB9, 0xAE, 0x6, 0xE3, 0x81, 0xA6, 0xE3, 0x82, 0x99, - 0x3, 0xE4, 0xBB, 0x80, 0x8, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE8, 0x81, 0xBE, - 0x4, 0xD1, 0x83, 0xCC, 0x88, 0x3, 0x54, 0xCC, 0x8C, 0x3, 0x74, 0xCC, 0xAD, 0x3, 0xE4, 0xBB, 0x8C, - 0x5, 0xE1, 0xBE, 0xBF, 0xCC, 0x81, 0x4, 0xCE, 0x97, 0xCD, 0x85, 0x5, 0x65, 0xCC, 0x82, 0xCC, 0x89, - 0x3, 0xE7, 0x94, 0xBB, 0x3, 0xE7, 0x93, 0x8A, 0x3, 0x48, 0xCC, 0xA3, 0x3, 0xE5, 0xA1, 0x9E, 0x3, - 0x4F, 0xCC, 0x87, 0x3, 0x68, 0xCC, 0xAE, 0x6, 0xE0, 0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0x3, 0x4E, 0xCC, - 0x80, 0x3, 0xE9, 0x9A, 0xB7, 0x6, 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7, 0x6, 0xE3, 0x81, 0x97, 0xE3, - 0x82, 0x99, 0x3, 0x69, 0xCC, 0xB0, 0x3, 0xE8, 0x80, 0x81, 0x3, 0xE5, 0xBE, 0x8B, 0x3, 0xE8, 0x93, - 0xBC, 0x3, 0xE4, 0xA6, 0x95, 0x3, 0xE7, 0xBD, 0xB2, 0x6, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99, 0x8, - 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x4, 0xF0, 0xA9, 0x85, 0x85, 0x3, 0xE7, 0x83, - 0x99, 0xC, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB1, 0x3, 0x66, - 0xCC, 0x87, 0x4, 0xCE, 0x99, 0xCC, 0x86, 0x4, 0xCF, 0x81, 0xCC, 0x94, 0x6, 0xCE, 0xB1, 0xCC, 0x93, - 0xCC, 0x81, 0x2, 0xCC, 0x80, 0x3, 0x5A, 0xCC, 0x8C, 0xC, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85, - 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0x6, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x95, 0x8, 0xCF, 0x89, 0xCC, - 0x94, 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE4, 0x83, 0xA3, 0x3, 0x56, 0xCC, 0xA3, 0x8, 0xCE, 0x91, 0xCC, - 0x94, 0xCD, 0x82, 0xCD, 0x85, 0x5, 0x61, 0xCC, 0x86, 0xCC, 0x83, 0x3, 0xE3, 0x94, 0x95, 0x4, 0xF0, - 0xA4, 0x8E, 0xAB, 0x5, 0x4F, 0xCC, 0x82, 0xCC, 0x81, 0x4, 0xF0, 0xA2, 0xA1, 0x84, 0x3, 0x75, 0xCC, - 0x86, 0x3, 0xE8, 0x98, 0x92, 0x3, 0xE5, 0x8A, 0x9B, 0x3, 0x44, 0xCC, 0xA7, 0x3, 0x65, 0xCC, 0x86, - 0x3, 0xE8, 0xA3, 0xB8, 0x3, 0x47, 0xCC, 0xA7, 0x3, 0xE8, 0x8F, 0x9C, 0x3, 0xE3, 0xA4, 0x9C, 0x6, - 0xE3, 0x83, 0xB1, 0xE3, 0x82, 0x99, 0x6, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE, 0xB7, 0x3, 0xE6, 0x9D, - 0xBB, 0x3, 0xE6, 0xBF, 0xAB, 0x5, 0x73, 0xCC, 0xA3, 0xCC, 0x87, 0x3, 0x6F, 0xCC, 0x84, 0x8, 0xCE, - 0x97, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0x3, 0x67, 0xCC, 0x84, 0x4, 0xD7, 0x92, 0xD6, 0xBC, 0x3, - 0x79, 0xCC, 0x82, 0x5, 0x4F, 0xCC, 0x82, 0xCC, 0x80, 0x4, 0xD1, 0xB4, 0xCC, 0x8F, 0x5, 0x6F, 0xCC, - 0x88, 0xCC, 0x84, 0x5, 0x55, 0xCC, 0x88, 0xCC, 0x81, 0x3, 0x73, 0xCC, 0xA6, 0x3, 0x45, 0xCC, 0xA7, - 0x6, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x99, 0x3, 0x50, 0xCC, 0x87, 0x4, 0xD0, 0xA3, 0xCC, 0x8B, 0x3, - 0xE7, 0xAF, 0x89, 0x6, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8F, 0x3, 0xE7, 0x85, 0x85, 0x4, 0xD0, 0xB5, - 0xCC, 0x80, 0x4, 0xCE, 0x99, 0xCC, 0x93, 0x3, 0x65, 0xCC, 0xA7, 0x3, 0xE9, 0xA0, 0xA9, 0x3, 0xE7, - 0xB2, 0xBE, 0x3, 0x4B, 0xCC, 0xA7, 0x3, 0xE4, 0xBE, 0xBF, 0x3, 0xE9, 0xB1, 0x97, 0x6, 0xE3, 0x81, - 0xA4, 0xE3, 0x82, 0x99, 0x3, 0xE7, 0x99, 0xA9, 0x4, 0xF0, 0xA2, 0xAC, 0x8C, 0x3, 0xE5, 0x8D, 0x89, - 0x3, 0xE5, 0x8A, 0xB3, 0x3, 0x63, 0xCC, 0x81, 0x5, 0xE2, 0x88, 0xBC, 0xCC, 0xB8, 0x6, 0xE0, 0xA4, - 0xA1, 0xE0, 0xA4, 0xBC, 0x3, 0xE4, 0xB8, 0xB2, 0x3, 0xE6, 0xAE, 0xAE, 0x4, 0xF0, 0xA5, 0xA5, 0xBC, - 0x4, 0xF0, 0xA3, 0x91, 0xAD, 0x6, 0xE0, 0xB2, 0xBF, 0xE0, 0xB3, 0x95, 0x3, 0x47, 0xCC, 0x81, 0x6, - 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x81, 0x3, 0xE4, 0x8A, 0xA0, 0x3, 0xE6, 0xA1, 0x92, 0x6, 0xE3, 0x82, - 0x9D, 0xE3, 0x82, 0x99, 0x3, 0x65, 0xCC, 0x84, 0x3, 0x69, 0xCC, 0x91, 0x8, 0xCE, 0xA9, 0xCC, 0x94, - 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE6, 0x9A, 0x9C, 0x6, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x99, 0x6, 0xCE, - 0x97, 0xCC, 0x94, 0xCD, 0x82, 0x3, 0x49, 0xCC, 0x89, 0x4, 0xD7, 0x95, 0xD6, 0xB9, 0x6, 0xE0, 0xAC, - 0xA1, 0xE0, 0xAC, 0xBC, 0x3, 0xE5, 0x86, 0x97, 0x3, 0x79, 0xCC, 0x81, 0x4, 0xD0, 0xA3, 0xCC, 0x86, - 0x3, 0x41, 0xCC, 0xA5, 0x3, 0x7A, 0xCC, 0x87, 0x3, 0xE6, 0xA8, 0x93, 0x3, 0x4E, 0xCC, 0x87, 0x4, - 0xCF, 0x89, 0xCC, 0x80, 0x4, 0xD7, 0x99, 0xD6, 0xB4, 0x3, 0x6F, 0xCC, 0x83, 0x3, 0x3C, 0xCC, 0xB8, - 0x3, 0xE8, 0x81, 0xAF, 0x4, 0xCE, 0xB1, 0xCD, 0x82, 0x3, 0xE8, 0x9D, 0xAB, 0x3, 0xE7, 0x81, 0xB0, - 0x3, 0xE3, 0x9B, 0xAE, 0x3, 0xE7, 0x90, 0xA2, 0x3, 0xE7, 0xB9, 0x81, 0x3, 0xE6, 0xB2, 0x88, 0x3, - 0xE3, 0xBA, 0xAC, 0x4, 0xCF, 0x81, 0xCC, 0x93, 0x4, 0xF0, 0xA4, 0x89, 0xA3, 0x3, 0xE5, 0x85, 0x94, - 0x6, 0xE0, 0xA8, 0xB2, 0xE0, 0xA8, 0xBC, 0x6, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x80, 0x4, 0xF0, 0xA5, - 0xB2, 0x80, 0x6, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0xE8, 0xAE, 0x80, 0x3, 0x4F, 0xCC, 0x89, - 0x6, 0xE0, 0xBE, 0xB3, 0xE0, 0xBE, 0x80, 0x6, 0xE0, 0xBE, 0xB2, 0xE0, 0xBE, 0x80, 0x3, 0x61, 0xCC, - 0x80, 0x3, 0x65, 0xCC, 0x91, 0x3, 0xE5, 0x85, 0xB7, 0x3, 0xE5, 0x87, 0x8C, 0x3, 0xE5, 0x96, 0x87, - 0x5, 0x4F, 0xCC, 0x83, 0xCC, 0x88, 0x8, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE3, - 0xA9, 0xAC, 0x5, 0x61, 0xCC, 0x86, 0xCC, 0x89, 0x3, 0xE8, 0xB3, 0x88, 0x3, 0x6B, 0xCC, 0xA3, 0x4, - 0xCE, 0xB5, 0xCC, 0x93, 0x3, 0xE5, 0x83, 0x8F, 0x3, 0x58, 0xCC, 0x87, 0x3, 0xE8, 0xBB, 0x8A, 0x8, - 0xF0, 0x91, 0x96, 0xB8, 0xF0, 0x91, 0x96, 0xAF, 0x6, 0xE3, 0x83, 0xBD, 0xE3, 0x82, 0x99, 0x3, - 0xE6, 0xA5, 0x82, 0x3, 0xE6, 0x8F, 0x84, 0x4, 0xD0, 0xBE, 0xCC, 0x88, 0x3, 0x44, 0xCC, 0x8C, 0x3, - 0x75, 0xCC, 0xA3, 0x4, 0xF0, 0xA0, 0xA8, 0xAC, 0x3, 0x77, 0xCC, 0x82, 0x3, 0xE4, 0xBE, 0x8B, 0x3, - 0xE5, 0x8F, 0xB1, 0x6, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0x4, 0xCE, 0xB1, 0xCC, 0x80, 0x3, 0xE8, - 0xA1, 0x8C, 0x3, 0xE8, 0xB2, 0xAB, 0x3, 0x4E, 0xCC, 0x8C, 0x3, 0xE7, 0x8A, 0xAF, 0x3, 0xE5, 0x8C, - 0xBF, 0x4, 0xF0, 0xA0, 0xA0, 0x84, 0x5, 0x61, 0xCC, 0xA3, 0xCC, 0x82, 0x3, 0xE5, 0xA1, 0x80, 0x3, - 0xE4, 0x97, 0xB9, 0x4, 0xF0, 0xA7, 0x83, 0x92, 0x5, 0xE2, 0x8A, 0xB5, 0xCC, 0xB8, 0x3, 0xE5, 0x92, - 0x9E, 0x3, 0x65, 0xCC, 0x83, 0x3, 0xE6, 0x9B, 0xB4, 0x3, 0xE7, 0x81, 0x8A, 0x3, 0xE4, 0x80, 0xB9, - 0x3, 0x6F, 0xCC, 0x82, 0x3, 0xE7, 0xB9, 0x85, 0x2, 0xC2, 0xB7, 0x3, 0x62, 0xCC, 0xA3, 0x4, 0xCE, - 0xA5, 0xCC, 0x86, 0x3, 0xE6, 0x8E, 0xA9, 0x4, 0xF0, 0xA5, 0x9A, 0x9A, 0x3, 0xE9, 0x9C, 0xB2, 0x3, - 0xE8, 0x8A, 0x91, 0x3, 0x55, 0xCC, 0xAD, 0x3, 0xE5, 0xB8, 0xBD, 0x6, 0xCE, 0x99, 0xCC, 0x94, 0xCC, - 0x81, 0x3, 0x69, 0xCC, 0x83, 0x3, 0x70, 0xCC, 0x87, 0x3, 0x65, 0xCC, 0x87, 0x3, 0xE5, 0x88, 0x83, - 0x3, 0xE7, 0x87, 0x8E, 0x3, 0x6F, 0xCC, 0x89, 0x4, 0xF0, 0xA3, 0x8E, 0x93, 0x3, 0xE9, 0x89, 0xB6, - 0x3, 0xE6, 0x9E, 0x97, 0x3, 0xE8, 0x99, 0xA7, 0x3, 0xE8, 0xB7, 0xB0, 0x3, 0xE9, 0x82, 0x8F, 0x3, - 0x77, 0xCC, 0x87, 0x3, 0xE3, 0xB0, 0x98, 0x3, 0x55, 0xCC, 0x84, 0x3, 0xE9, 0xA3, 0xA2, 0x3, 0xE6, - 0xA0, 0x9F, 0x3, 0xE7, 0x9E, 0xA7, 0x6, 0xE3, 0x81, 0x95, 0xE3, 0x82, 0x99, 0x6, 0xE0, 0xBE, 0xA6, - 0xE0, 0xBE, 0xB7, 0x4, 0xCE, 0xB1, 0xCC, 0x93, 0x3, 0x75, 0xCC, 0x8F, 0x3, 0xE8, 0xAB, 0x92, 0x5, - 0xE2, 0x89, 0xB7, 0xCC, 0xB8, 0x6, 0xCE, 0xB7, 0xCC, 0x81, 0xCD, 0x85, 0x5, 0xE2, 0x89, 0x83, - 0xCC, 0xB8, 0x3, 0xE6, 0x93, 0x84, 0x4, 0xCF, 0x85, 0xCC, 0x93, 0x3, 0xE7, 0xB5, 0x9B, 0x3, 0x79, - 0xCC, 0x83, 0x3, 0x69, 0xCC, 0x8F, 0x3, 0xE9, 0x9B, 0xB7, 0x4, 0xF0, 0xA3, 0xBD, 0x9E, 0x5, 0x72, - 0xCC, 0xA3, 0xCC, 0x84, 0xC, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, - 0xAE, 0x3, 0xE6, 0x88, 0x9B, 0x4, 0xD0, 0x93, 0xCC, 0x81, 0x6, 0xE0, 0xA6, 0xAF, 0xE0, 0xA6, 0xBC, - 0x8, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0x4, 0xF0, 0xA6, 0x94, 0xA3, 0x3, 0xE9, 0x87, - 0x8C, 0x8, 0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92, 0xBA, 0x4, 0xF0, 0xA7, 0xBC, 0xAF, 0x3, 0xE9, - 0x9C, 0xA3, 0x3, 0x6E, 0xCC, 0x80, 0x6, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x3, 0x61, 0xCC, 0x84, - 0x4, 0xF0, 0xA6, 0xBC, 0xAC, 0x3, 0xE7, 0xA9, 0x8A, -}; - -static const uint32_t _swift_stdlib_nfd_decomp_indices[2061] = { - 0x2F93B, 0x1400EE, 0x241E94, 0x36F874, 0x44FA9B, 0x56F87F, 0x641F44, 0x82F86A, 0x92F9DA, 0xA01EA6, - 0xB8307A, 0xD4F9DB, 0xE4FAA1, 0xF400DC, 0x104F96E, 0x114F91A, 0x126F9AE, 0x1341EA5, 0x14C010B, - 0x15C095D, 0x178FB41, 0x18CFA85, 0x19D134B, 0x1C2F991, 0x1D2F828, 0x1E01F89, 0x1FC2ADC, 0x216F9F9, - 0x22401B0, 0x2340108, 0x24400C7, 0x256F8BC, 0x266F8AC, 0x2741F79, 0x288F951, 0x29800F2, 0x2AAFA14, - 0x2BCF9A8, 0x2CCFAD2, 0x2DCF9BE, 0x2ECF918, 0x2FC1EC2, 0x314FA1C, 0x324FAB8, 0x3341F39, 0x3481ECD, - 0x35AF9B8, 0x36AF841, 0x378095A, 0x396F933, 0x3A400D6, 0x3B4038C, 0x3C8FB1F, 0x3DEF9F2, 0x3EC1F9C, - 0x4101F9A, 0x436F82F, 0x444FA8E, 0x456F90D, 0x46AF99C, 0x478F942, 0x488FA6C, 0x49EF8D4, 0x4AC012F, - 0x4BC011D, 0x4CC1E20, 0x4DC01D1, 0x4EC1EEA, 0x506FA05, 0x51401D4, 0x524FAD3, 0x5341B12, 0x550FA58, - 0x5601F1A, 0x57C0958, 0x598F995, 0x5AAF958, 0x5BAF879, 0x5CAF918, 0x5D800D2, 0x5E8FA51, 0x5F8F9E8, - 0x6080401, 0x61CFABB, 0x62C03AB, 0x640F919, 0x652F9F1, 0x666F830, 0x6741E52, 0x68C00E5, 0x69C095F, - 0x6B81F6F, 0x6D6F865, 0x6E409DC, 0x7001E4C, 0x718020D, 0x72809CB, 0x744F9AD, 0x756F94B, 0x764FAB7, - 0x774FA15, 0x786FA1A, 0x794020E, 0x7A4FA2C, 0x7B6F8A5, 0x7C41E30, 0x7D400EB, 0x7E4FA34, 0x7F401CF, - 0x806F9AF, 0x816F8FA, 0x82401E3, 0x8380DDD, 0x86000F1, 0x8701F0E, 0x88C00D9, 0x89EF848, 0x8AEF9B2, - 0x8BCF98E, 0x8CEF8FC, 0x8DC1E8E, 0x8EC1EDE, 0x906F945, 0x914F91B, 0x9241FC1, 0x9381F99, 0x956F9B6, - 0x966F895, 0x3B41FF9, 0x976F9CF, 0x984307D, 0x9A01E83, 0x9B01F4D, 0x9CC03CD, 0x9E0FAA8, 0x9F0FA81, - 0xA00F97F, 0xA101E04, 0xA22F9DB, 0xA301E32, 0xA40F92D, 0xA52FA03, 0xA601F0F, 0xA7C3073, 0xA98F96A, - 0xAA81E77, 0xAB804EE, 0xACEFA15, 0xADCFABA, 0xAEC01FC, 0xB000103, 0xB12F80C, 0xB22F8C4, 0xB300230, - 0xB48015A, 0xB58F925, 0xB680144, 0xB781FA4, 0xB9C1F35, 0xBB81F81, 0xBD40104, 0xBE6F9E9, 0xBF41EAF, - 0xC0C1F1C, 0xC281F11, 0xC3CF999, 0xC4EFA17, 0xC5C1E3B, 0xC6C1EAC, 0xC86F92E, 0xC94FA57, 0xCA6F8BB, - 0xCB400CE, 0xCC401F0, 0xCD6F825, 0xCE41E15, 0xCFC0DDE, 0xD1AF859, 0xD2CFAAA, 0xD3C0226, 0xD4CF9CC, - 0xD5CF94B, 0xD6C06C2, 0xD801FB2, 0xD9C0BCC, 0xDBAF812, 0xDCC03AF, 0xDE0FA79, 0xDF01F2A, 0xE0CF940, - 0xE1C0625, 0xE301E1E, 0xE42F91A, 0xE50F9F9, 0xE60FAA7, 0xE72F9FD, 0xE86F8CB, 0xE96F9FC, 0xEA40161, - 0xEB40227, 0xEC4FB38, 0xEDAF9F3, 0xEE81E65, 0xF02F9EE, 0xF10F9E6, 0xF20FA35, 0xF30F91F, 0xF42F94F, - 0xF501E95, 0xF600206, 0xF70305E, 0xF8EF801, 0xF9CF977, 0xFAC09CC, 0xFCAF804, 0xFD81FAF, 0xFFC1E91, - 0x100CFA3C, 0x101C2278, 0x1036F856, 0x10441FDE, 0x105CF9B9, 0x106EF9F7, 0x1080F923, 0x10900130, - 0x10A01FF8, 0x10B4F989, 0x10C4F9D3, 0x10D4F9CD, 0x10E4FA83, 0x10F4F93A, 0x11040386, 0x11180931, - 0x1136F892, 0x1148FAB6, 0x1158015B, 0x1168F975, 0x117AF8A1, 0x118AF8D9, 0x11981E90, 0x11A8FA5C, - 0x11B8F9B3, 0x11CAF810, 0x11D8F93D, 0x11E81EF2, 0x11FAF880, 0x1208FA66, 0x121AF8DD, 0x122C2001, - 0x123C0105, 0x124EF9C9, 0x125C03AE, 0x1270FA53, 0x1282F850, 0x1290FAD9, 0x12A2F91E, 0x12B2F85D, - 0x12C0F931, 0x12D2F8E2, 0x12E01F3E, 0x12FCF976, 0x130C1F6C, 0x132AF971, 0x133AF8CE, 0x134AF8FF, - 0x1358FA3E, 0x1368F95B, 0x1378F9D5, 0x1388F939, 0x13981B0E, 0x13B42275, 0x13CC1FD1, 0x13E0F900, - 0x13F0F983, 0x14001F68, 0x141404D1, 0x1428FA6D, 0x1438FA98, 0x14481EEE, 0x146000DD, 0x1472F975, - 0x1484FAB2, 0x1496F9F8, 0x14A4F998, 0x14B41FA0, 0x14D0012B, 0x14E2F8DB, 0x14F01FE7, 0x150C1EC6, - 0x15241F61, 0xF40F93B, 0x15380BCB, 0x1556F98A, 0x1568011A, 0x1578FA4C, 0x15880D4B, 0x15A41E5C, - 0x15BEF947, 0x15CC30D0, 0x15E8FAA0, 0x15F8FAAE, 0x16083054, 0x16241E68, 0x163CF9A1, 0xE6F930, - 0x164C2126, 0x165AF82A, 0x166803CE, 0x167C00D5, 0x168C22AE, 0x16A4F9F5, 0x16B41E18, 0x16C4F971, - 0x16D6FA10, 0x16E81E4A, 0x16F8040D, 0x170CF9DD, 0x171C0200, 0x172C1EDA, 0x17440139, 0x17541EDC, - 0x176C30B8, 0x178800E3, 0x1798FA3D, 0x17A81F23, 0x17C41FC6, 0x17DAFA16, 0x17E8F90A, 0x17FAF8F4, - 0x18081EF5, 0x18181F82, 0x183CF9B6, 0x184C30D9, 0x18681ED4, 0x18801EBC, 0x189000CD, 0x18A00F69, - 0x18BCFA7B, 0x18CCFA49, 0x18DCF962, 0x18EEF934, 0x18FCF9A6, 0x190CF9EA, 0x191C00C1, 0x192C1F90, - 0x194804E6, 0x195EF9E5, 0x19700477, 0x1984FAB5, 0x1996F8D3, 0x19A430D4, 0x19C000CA, 0xC94F996, - 0x19D2F888, 0x19E2F8AB, 0x19F00202, 0x1A02F87E, 0x1A1004EA, 0x1A24FA67, 0x1A3401D0, 0x1A44FA41, - 0x1A56F898, 0x1A6AF926, 0x1A7EF9F0, 0x1A8EF9DE, 0x1A9C1FB9, 0x1AB01EF7, 0x1AC03094, 0x1ADC1E8C, - 0x1AEC1E19, 0x1AFC1E50, 0x1B141E9B, 0x1B281F98, 0x1B46F8E6, 0x1B54013E, 0x1B6401DC, 0x1B7C1EE0, - 0x1B96F8F5, 0x1BA6F95D, 0x1BBAF995, 0x1BC81E88, 0x1BD910AB, 0x1BFEF8FE, 0x1C0C0A36, 0x1C281E93, - 0x1C3AF89E, 0x1C4AF87D, 0x1C5C01FF, 0x1C700211, 0x1C801E17, 0x1C980106, 0x1CAAF9AA, 0x1CB81EE8, - 0x1CD2F9E7, 0x1CE01FE9, 0x1CF6F9C8, 0x1D04F98C, 0x1D16F815, 0x1D2404D3, 0x1D380385, 0x1D4C1E13, - 0x1D5C1EC9, 0x1D6CFA73, 0x82F86B, 0x1D7CFB48, 0x1D901FC2, 0x1DAEF9CB, 0x1DC00439, 0x1DD4F937, - 0x1DE40163, 0x1DF41EB9, 0x1E06F977, 0x1E181E1C, 0x1E300624, 0x1E46F976, 0x1E56F873, 0x1E642262, - 0x1E7EF882, 0x1E8CFB2F, 0x1EA0F974, 0x1EB01FB3, 0x1EC4021F, 0x1ED4FA36, 0x1EE6F9F4, 0x1EF6F96C, - 0x1F04FAC4, 0x1F14FA26, 0x1F2430D1, 0x1F42F9E4, 0x1F52F8BE, 0x1F64F9D2, 0x1F7400EF, 0x1A24FA25, - 0x1F84013D, 0x1F941EBB, 0x1FA41F3F, 0x1FC2F822, 0x1FD01F62, 0x1FEC015F, 0x1FFEF9EA, 0x200EF906, - 0x2020095B, 0x203CF9AF, 0x204C01DF, 0x2064F9E3, 0x20740114, 0x208430B0, 0x20A01EB2, 0x20B8F90D, - 0x20CAF8C9, 0x20D8F954, 0x20E830BA, 0x21041E75, 0x2116F8D2, 0x212401ED, 0x213C01D9, 0x21541F08, - 0x21681FAA, 0x218CF9A0, 0x219C0155, 0x21AEFA07, 0x21BC06C0, 0x21D01E0A, 0x21E01E74, 0x21F01F3B, - 0x220C1E97, 0x221C0160, 0x222EF9A8, 0x223C1F84, 0x22600134, 0x2270F991, 0x22801FE2, 0x229CF9BC, - 0x22AC0F57, 0x22C8FB39, 0x22DC1FBE, 0x22E81B43, 0x2304FA5D, 0x23141EE6, 0x2324FAB3, 0x23341E58, - 0x2344F921, 0x2354F953, 0x23640162, 0x2376F9E2, 0x2386F9A6, 0x23981FFD, 0xD4F961, 0x23A6F939, - 0x23B8FA02, 0x23C80453, 0x23DCF981, 0x23ECF9EE, 0x23FCFA84, 0x240CF91E, 0x241EFA19, 0x242EF974, - 0x243EF986, 0x244C0DDA, 0x2468FB47, 0x247C1F34, 0x249AF816, 0x24AEF935, 0x24C2F9A5, 0x24D4F92C, - 0x24E4F946, 0x24F4014C, 0x250400E9, 0x25141E7D, 0x25241FB0, 0x253AF9E0, 0x254C1EC1, 0x25640341, - 0x257000DA, 0x2580F9D4, 0x25901EA4, 0x25A81FFC, 0x25BC1E66, 0x25D41EE1, 0x25EC012E, 0x25FCF985, - 0x260EF93C, 0x26201E0D, 0x26300D4C, 0x264C1E06, 0x265EF9C3, 0x266CFACA, 0x267EF948, 0x268C1F13, - 0x26A8F99B, 0x26B8FA45, 0x26C81F22, 0x26E6F9CA, 0x26F4F947, 0x2704FA46, 0x2714F915, 0x2724FA6A, - 0x27341EF0, 0x274EF842, 0x275EF9D1, 0x276C020F, 0x277C1F73, 0x27901EC7, 0x27A81FFB, 0x27BC1FED, - 0x27D0FA4D, 0x27E0F9F3, 0x27F0F92A, 0x19E0FA89, 0x2802F96F, 0x28100F81, 0x282EF981, 0x283C011B, - 0x284EF950, 0x285CF9BD, 0x286CF98D, 0x287EF9D2, 0x288C2274, 0x28A4FA05, 0x28B41F9F, 0x28D81FBA, - 0x28EEF88E, 0x28FC1FCD, 0x2916F8EC, 0x292AF897, 0x293EF993, 0x294C1E7B, 0x2966F854, 0x2976F863, - 0x298422AF, 0x299CFB3A, 0x29B00176, 0x29C2F87A, 0x29D01EBA, 0x29E0FAC3, 0x29F2F9D6, 0x2A000169, - 0x2A100143, 0x2A200F52, 0x2A3C1E63, 0x2A4CF9CA, 0x2A5CFACB, 0x2A6C1E34, 0x2A7EF9E1, 0x2A901FBC, - 0x2AA4FA88, 0x2AB4FAA6, 0x2AC422E1, 0x2ADEF9EB, 0x2AECF943, 0x2AFC00E4, 0x2B0CF979, 0x2B1CF9B2, - 0x2B2CF908, 0x2B3C0156, 0x2B4C1FAE, 0x2B70014E, 0x2B80FA91, 0x2A5EF9FE, 0x2B9115BB, 0x2BB4015D, - 0x2BC4F993, 0x2BD4FA30, 0x2BE41E64, 0x2BFEF8EA, 0x2C0C015E, 0x2C1C0218, 0x2C2CF93F, 0x2C3C1FE0, - 0x2C5004F0, 0x2C66F985, 0x2C741F54, 0x2C92F907, 0x2CA0F9FF, 0x2CB2F83F, 0x2CC01E6C, 0x2CD2F99F, - 0x2CE2F857, 0x2CF0F9F7, 0x2D001FEB, 0x2D141E2A, 0x2D241E03, 0x2D341EE4, 0x2D441E67, 0x2D5EF836, - 0x2D6C1F29, 0x7E6F827, 0x2D800120, 0x2D92F88D, 0x2DA0F978, 0x2DB2F8D6, 0x2DC2F9AC, 0x2DD2F9D0, - 0x2DE2F9A2, 0x2DF01F60, 0x2E06F86E, 0x2E143071, 0x2E30F97C, 0x2E4030FA, 0x2E5CF988, 0x2E6C1E5F, - 0x2E7EF83D, 0x27403CC, 0x2E8CF9A7, 0x2E9CF96B, 0x2EAC1F21, 0x2EC01E35, 0x2ED2F966, 0x2EE0011F, - 0x2EF000FC, 0x2F00F97E, 0x2F12F90F, 0x2F20F9B1, 0x2F32F987, 0x2F46F93E, 0x2F56F871, 0x2F681EA2, - 0x2F7AF9CC, 0x2F8CF9CF, 0x2F9EF915, 0x2FACF9D1, 0x2FBC1F95, 0x2FE004E3, 0x2FF4F911, 0x3006F9B9, - 0x3014F984, 0x3026F960, 0x3036F8CF, 0x304400F3, 0x3056FA09, 0x30680233, 0x3078010C, 0x308804F9, - 0x309CF9FE, 0x30AEF988, 0x30C01E08, 0x30D81FA6, 0x30FCF950, 0x310CFB36, 0x31200124, 0x31300F43, - 0x314C1E25, 0x315C00CB, 0x316EF9E6, 0x317C1F5D, 0x319AF9C7, 0x31A81E7F, 0x2AB4FA17, 0x31BAF9B4, - 0x31C8FB4D, 0x31DC1EEF, 0x31F41E92, 0x3206F936, 0x3216F8BA, 0x3224F909, 0x3234F929, 0x3246F849, - 0x325401FE, 0x32681F19, 0x327C1F07, 0x100EF878, 0x3299109A, 0x32BCF924, 0x32CC0102, 0x32DEF809, - 0x32EC1ED7, 0x3306F81C, 0x3318011C, 0x33280B94, 0x33441EEB, 0x335C01D8, 0x33741B0A, 0x339000C4, - 0x33A0FACF, 0x33B40118, 0x33C6F9BE, 0x33D6F8B9, 0x33E6F9FA, 0x33F6F870, 0x3406F847, 0x3416F86D, - 0x34241FC8, 0x34381F86, 0x345EF8BD, 0x346EF85E, 0x347D134C, 0x34A00165, 0x34B2F9A7, 0x34C000E7, - 0x2A5EF9FF, 0x34D2F98C, 0x34E2F81D, 0x34F0F964, 0x3500017A, 0x3512F94D, 0x3526F87C, 0x3534F99E, - 0x3544F9DF, 0x35541E54, 0x3564F966, 0x3576F875, 0x35841E4D, 0x359C1B0C, 0x35B804DA, 0x35CEF9EC, - 0x35DCF9BB, 0x1136F891, 0x35EEF964, 0x35FC016F, 0x360EF929, 0x361C1B06, 0x36380135, 0x3648FA8F, - 0x36581F14, 0x3674012C, 0x368403D3, 0x3699D160, 0x9CC1F7B, 0x125C1F75, 0x36CC0210, 0x36DC04E4, - 0x36F0F9CB, 0x3702F92C, 0x37101EDD, 0x3729D15E, 0x374EF844, 0x375C0343, 0x37681F56, 0x3784F9C7, - 0x37940CCB, 0x37BEF860, 0x37D00171, 0x37E0010D, 0x37F0FA60, 0x3802F9A0, 0x3812F88B, 0xC94FAB0, - 0x382001A1, 0x3830F9AA, 0x3840FA71, 0x3850FA2E, 0x3860220C, 0x38780125, 0x284CFAAB, 0x3888FA0A, - 0x38981F5F, 0x38B41026, 0x38D0F9D0, 0x38E0FA7F, 0x38F0017B, 0x3902F920, 0x39101F97, 0x39341EB6, - 0x394EF8C2, 0x395C01E8, 0x396C0BCA, 0x398AF814, 0x399804E2, 0x39AC1F6E, 0x39C80F73, 0x39E4FA48, - 0x39F41F0D, 0x3A101ED5, 0x3A2AF9D3, 0x3A3C1E2E, 0x3A540B4B, 0x3A701F53, 0x3A8C0388, 0x3AA0FA09, - 0x3AB0F9DC, 0x3AC2F944, 0x3AD4FB3C, 0x3AEAF85B, 0x3AF82260, 0x3B0806D3, 0x3B1C1F8A, 0x3B401FD6, - 0x3B56FA0D, 0x3B6430AE, 0x3B8001AF, 0x3B901EE3, 0x3BAAF9B3, 0x3BB9D1BC, 0x3BDC0622, 0x3BF00F4D, - 0x3C0C1E55, 0x3C1CFA07, 0x3C2EF803, 0x3C400214, 0x3C50F9C6, 0x3C60F95E, 0x3C701EA7, 0x3C8AF85A, - 0x3C981E86, 0x3CA8305C, 0x3CC404F5, 0x3CD8FA1E, 0x3CE800F9, 0x3CF81E47, 0x3D0AF818, 0x3D1801E6, - 0x3D2AF90E, 0x3D381F01, 0x3D4C04F8, 0x3D60012D, 0x3D7022AD, 0x3D881E42, 0x3D981E99, 0x3DA81E4F, - 0x3DC01E26, 0x3DD004ED, 0x3DE6F9C5, 0x3DFAF88C, 0x3E0822EC, 0x3E201E62, 0x3E301EC5, 0x3E4AF851, - 0x3E58FA19, 0x3E68212A, 0x3E703052, 0x3E8C1F26, 0x3EA81E60, 0x3EBAF912, 0x3EC8F9F1, 0x3ED80C48, - 0x3EF4FA90, 0x3F041FAD, 0x3F2AFA0F, 0x3F3AF862, 0x3F48FA32, 0x3F5800D1, 0x26BAF901, 0x3F6801E1, - 0x3F80F904, 0x3F90F932, 0x3FA2F9A1, 0x3FB003AA, 0x3FC5D161, 0x3FF81F6A, 0x4016FA1B, 0x4024FAB4, - 0x40341E81, 0x40441F2E, 0x4062F972, 0x4074FB30, 0x40881EBE, 0x40A0F956, 0x40B0010F, 0x40C01F48, - 0x40D4F9E5, 0x40E4F9E2, 0x40F401E0, 0x410C04DE, 0x4120305A, 0x413C01FB, 0x4154F9C5, 0x4164FA86, - 0x41741FEA, 0x418AF9DD, 0x419CFB4A, 0x41B01F1B, 0x41CEF905, 0x41DEF9AB, 0x41F01B40, 0x420EF8A0, - 0x421CFA2D, 0x422EF837, 0x423CFA75, 0x424EF83E, 0x425C1ECB, 0x426C1ED8, 0x4286F864, 0x42941E12, - 0x42A6F8C3, 0x42B6F8B4, 0x42C41EE2, 0x42DC00C8, 0x42EEF927, 0x4300037E, 0x43081E70, 0x4318226D, - 0x43301F67, 0x3832F86F, 0x434CF98F, 0x435C021B, 0x436EFA0A, 0x437EF91B, 0x4390FA4B, 0x43A01F43, - 0x43BC0457, 0x43D0F9CE, 0x43E030D7, 0x3236F8D8, 0x43FC1E02, 0x440C01DB, 0x4426F866, 0x4436F952, - 0x444AF9E3, 0x445AF84F, 0x275CFAC0, 0x4468FA1B, 0x447AF92B, 0x44881F71, 0x449EF829, 0x44ACF9D7, - 0x44BCF9AE, 0x44CC3077, 0x44E8F91C, 0x44F80A5B, 0x45141FB4, 0x4530011E, 0x454004F3, 0x45540212, - 0x4566FA18, 0x4574219B, 0x458C1F72, 0x45A0F917, 0x45B2F808, 0x45C2FA1D, 0x45D41FCA, 0x45E803B0, - 0x46041F02, 0x4622F99D, 0x463001EF, 0x464404EF, 0x46581F6B, 0x46741EF3, 0x4686F8F6, 0x469400FB, - 0x46A43050, 0x46C02204, 0x46D8021A, 0x46EAF853, 0x46FAF869, 0x47081FEF, 0x47103070, 0x472CFB2D, - 0x474AF8F9, 0x475CF9ED, 0x476CFA82, 0x477CF98B, 0x478C0201, 0x479EF8C0, 0x47AEF845, 0x47BC1FF6, - 0x1ED4FA78, 0x47D2F984, 0x47E001DE, 0x15BEF946, 0x47FAF900, 0x48081F66, 0x4826F8B2, 0x48341F28, - 0x4848F994, 0x485AF8F0, 0x486CF969, 0x487EF990, 0x488EF924, 0x489C0451, 0x48B2F97F, 0x48C01E37, - 0x48D0FA33, 0x48E01E2C, 0x48F01E98, 0x49000128, 0x49100112, 0x49201EA1, 0x49301E80, 0x4942F999, - 0x49502226, 0x49680FA2, 0x498400DB, 0x49941EB7, 0x49AC2289, 0x49C4F986, 0x49D6F820, 0x49E4022F, - 0x49F41FE1, 0x4A08F9EC, 0x4A18FAD1, 0x4A2CFB31, 0x4A4004DD, 0x4A541F59, 0x4A6822EB, 0x4A801E51, - 0x4A9800F6, 0x4AA8F90C, 0x4AB8FA2A, 0x4AC804D7, 0x4ADEF84B, 0x4AEC1EA9, 0x4B04FAC1, 0x4B14F90F, - 0x4B241EB0, 0x4B3C2329, 0x4B4C21CD, 0x4B66F890, 0x4B741E53, 0x4B8C0231, 0x4BA40173, 0x446AF956, - 0x267CFAA9, 0x4BB40178, 0x4BC41F64, 0x4BE000C5, 0x4BF01FC7, 0x4C0C1F3C, 0x4C28F9F8, 0x4C38F982, - 0x3404FA7A, 0x4C4AFA0C, 0x4C58F92B, 0x4C6AF90A, 0x4C781E1D, 0x4C92F925, 0x4CA2F922, 0x4CB2F813, - 0x4CC01E8F, 0x4CD0022A, 0x4CE800CF, 0x4CFAFA04, 0x4D081F9E, 0x4D2C1F41, 0x4D40FAC7, 0x4D501F40, - 0x4D641F88, 0x4D82F96E, 0x4D92F9C0, 0x4DA2F80D, 0x4DB6F84E, 0x4DC4F948, 0x4DD4013A, 0x4DE4020C, - 0x4DF40400, 0x4E08FB2E, 0x4E1C1E3A, 0x4E2CFB4C, 0x4E401F93, 0x4E64095E, 0x4E8030B2, 0x31B8F936, - 0x4E9EF95B, 0x4EAEF8B7, 0x4EBEF9BA, 0x45E81FE3, 0x4ECC1F9D, 0x4EF0FA38, 0x4F02F9C4, 0x4F101E46, - 0x4F20FABC, 0x4F300213, 0x4B04FA65, 0x4F40FB2A, 0x4F541E6D, 0x4F64FAD5, 0x4F7800EC, 0x4F883069, - 0x4FA400C0, 0x4FB4FA63, 0x4FC6F839, 0x4FD4F987, 0x4FE41E27, 0x4FF41E8D, 0x500430C9, 0x5022F881, - 0x50301FD2, 0x504EF876, 0x505C1F49, 0x1D381FEE, 0x50701F2C, 0x508C0123, 0x509C04DF, 0x50B2F8F1, - 0x50C0010A, 0x50D0013B, 0x50E030C5, 0x50FEF8A9, 0x510C1EC0, 0x5124FB46, 0x513AF877, 0x51480F93, - 0x5166F89D, 0x5176F838, 0x51881E45, 0x519801FD, 0x51AC0B5D, 0x51C8045C, 0x51DEF90C, 0x51EC219A, - 0x52041FC3, 0x52180205, 0x522821AE, 0x5242F872, 0x52500168, 0x526000FF, 0x5271D1C0, 0x52A6F968, - 0x52B6F9ED, 0x52CAF887, 0x52D8016B, 0x52E8FA50, 0x52F8013C, 0x53081E39, 0x532000C9, 0x53301E6B, - 0x5340FA99, 0x53501FCB, 0x536401D2, 0x5374F933, 0x53841E89, 0x5396F8BF, 0x53A5112E, 0x53C8304E, - 0x53E41E7C, 0x53F4016C, 0x540422E2, 0x541C1F8E, 0x54401F91, 0x545EF955, 0x54701EF4, 0x548001E7, - 0x54900119, 0x54A0FA3B, 0x54B2F994, 0x54C030C7, 0x54DEF8AF, 0x54EC1FA8, 0x2CD0FA5F, 0x550AFA0E, - 0x55181F96, 0x553C00C2, 0x554CFA70, 0x555EF961, 0x55703074, 0x558CF9C3, 0x559CFA37, 0x2B2CFACE, - 0x55AC1F7A, 0x55C0FB40, 0x55D4FA4E, 0x55E400D3, 0x55F6FA08, 0x5604FA80, 0x5614FA01, 0x5626F913, - 0x56341B08, 0x5650F960, 0x5660FA94, 0x5672F858, 0x568001CE, 0x569000CC, 0x56A01E73, 0x56B0F944, - 0x56C2F97E, 0x56D41FD9, 0x56EAF889, 0x56FEF921, 0x570CF963, 0x571C30F7, 0x5738F91D, 0x574AF81A, - 0x575AF807, 0x5768F94F, 0x57780217, 0x578AF8EF, 0x5798FA56, 0x57A8F9B7, 0x5798FAAD, 0x57B8FA7C, - 0x57C8F9B4, 0x57D82209, 0x57F01ED9, 0x5808FB2C, 0x1986F9BB, 0x58241FE6, 0x583AFA13, 0x584C1EC4, - 0x58641F6D, 0x58801EED, 0x5898FAAC, 0x58A81FB1, 0xADCFA22, 0x58BCFA42, 0x58CCF927, 0x58DDD164, - 0x59101FFA, 0x5924F9BA, 0x56FCFA9E, 0x59341F45, 0x5952F911, 0x59641FA1, 0x598000E8, 0x59901FA5, - 0x59B42247, 0x59CCFAD7, 0x59E01E49, 0x59F0F9F6, 0x5A002249, 0x5A181E07, 0x5A282284, 0xF22F82D, - 0x5A401F37, 0x5A5CFA52, 0x5A6C1E85, 0x5A7C1E4B, 0x5A8CFAC2, 0x5A9C1E0E, 0x5AAEF821, 0x5ABEF943, - 0x5AD2F931, 0x5AE2F957, 0x5AF2F97B, 0x5B06F959, 0x5B141EAA, 0x5B2CFA9A, 0x5B3C022C, 0x5B56F896, - 0x5B640F75, 0x5B800137, 0x5B901E59, 0x5BA0FAD6, 0x5BB43060, 0x5BD004DC, 0x5BE4016E, 0x5BF6F982, - 0x5C041E01, 0x5C1403D4, 0x5C28F9E0, 0x5C381E6F, 0x5C481F24, 0x5C66F885, 0x5C741FAC, 0x5C98F9A3, - 0x5CA8014F, 0x5CBAF80A, 0x966F894, 0x5CCAF9CD, 0x5CD8F9FA, 0x5CE81EDF, 0x5D02F8F7, 0x5D14F992, - 0x5D241EA0, 0x5D341E1B, 0x5D44FA1A, 0xDCC1F77, 0x5D55109C, 0x5D781EF6, 0x5D88F99D, 0x5D981F83, - 0x5DBCF9D9, 0x5DCC04F4, 0x5DE01ECC, 0x5DF004E5, 0x5E0401E9, 0x20BAF8B1, 0x2D00038E, 0x5E141E16, - 0x5E2EF94C, 0x5E3CFA06, 0x5E4EF88F, 0x5E60F959, 0x5E701FD3, 0x5E8C04DB, 0x5EA2F983, 0x5EB0F920, - 0x48D2F826, 0x5EC01EE7, 0x5ED01FCF, 0x5EEAF8A8, 0x5EFAF923, 0x5F0C00E2, 0x5F1EF9C1, 0x5F2EF86C, - 0x5F400179, 0x5F5021CE, 0x5F6801E2, 0x1EA2F998, 0x5F7C30C0, 0x5F9830B6, 0x5FB6F94E, 0x5FC400EA, - 0x5FD4304C, 0x5FF01B3B, 0x600EFA11, 0x601C04C2, 0x2B80FA12, 0x6032F800, 0x60401E5B, 0x60502285, - 0x6068F99F, 0x6078FAA4, 0x60881EA3, 0x60981EF1, 0x60B2F868, 0x60C2F802, 0x5CB8FA31, 0x60D00A59, - 0x60EC021E, 0x60FC0174, 0x610C1E41, 0x39E4FA9C, 0x611EF89C, 0x612EF96D, 0x613CFAD8, 0x614C1FEC, - 0x6160FA74, 0x2A4CFA97, 0x6172F941, 0x61841E1A, 0x61941FF3, 0x61A81F5B, 0x61C4F973, 0x61D6F843, - 0x61E6F928, 0x61F40208, 0x6206F8D0, 0x62141E72, 0x6226F9D5, 0x62341FDA, 0x624AF8C5, 0x625AF98B, - 0x626AF8E4, 0x627AF9BC, 0x62880407, 0x629C1F31, 0x62B03076, 0x62CC22E3, 0x62E6F85F, 0x2724FACC, - 0x62F6F8B6, 0x6304F952, 0x6314FA95, 0x63240154, 0x5342F90B, 0x6334FB3E, 0x6348F99C, 0x277C03AD, - 0x63580623, 0x636CFA0D, 0x637C0203, 0x638CFAB1, 0x639EF980, 0x63B00121, 0x63C01E96, 0x63D0F9E7, - 0x63E2F89A, 0x63F02224, 0x64080A5A, 0x64241E82, 0x6434F94D, 0x64440150, 0x6456F883, 0x6464FA6B, - 0x647403CA, 0x6488015C, 0x649AF89B, 0x64A80148, 0x1A46F8C8, 0x64B81F12, 0x64D4F9B8, 0x15E8FA16, - 0x64E4FB33, 0x64F80374, 0x6506F89F, 0x651430DC, 0x6530038A, 0x65441E84, 0x65541F42, 0x9E2F940, - 0x1BA6F95E, 0x65701F1D, 0x658C1E0F, 0x659C1F27, 0x65BAF8C6, 0x65C8022D, 0x65E2F855, 0x65F2FA0B, - 0x6602F8B5, 0x6612F8AE, 0x662030AC, 0x663EF8DF, 0x664CFA0C, 0x665EF84D, 0x666C1EAE, 0x66840CC8, - 0x66A2F8CC, 0x66B2F916, 0x66C0F9E4, 0x66D0FAA2, 0x66E0FB4E, 0x66F6F919, 0x6704F94A, 0x6716F8F3, - 0x67241F4B, 0x52EAF953, 0x67401E29, 0x67501F0A, 0x676C017E, 0x677CFA3A, 0x678C1F36, 0x67AAF88A, - 0x18DEF938, 0x67B8F990, 0x67C8F9D6, 0x67D8307C, 0x67F41FF4, 0x68101F25, 0x4FB4FABF, 0x682C00D4, - 0x683EF95F, 0x684C1E38, 0x6864FB2B, 0x687AF94A, 0x68881E28, 0x689AF96A, 0x68A8226F, 0x68B803CB, - 0x68CC1ED6, 0x68E41F09, 0x68F8F967, 0x690AF9C6, 0x69181E23, 0x69281F52, 0x69440929, 0x6960FA7D, - 0x697001FA, 0x6988F914, 0x6998F926, 0x2DD0FABE, 0x69A81F4C, 0x69C6F8E9, 0x69D41FA7, 0x69F8F9F0, - 0x6A081E79, 0x6A2001D6, 0x324FA61, 0x6A3AF83B, 0x6A480344, 0x6A5EF96B, 0x6A70F9FB, 0x6A80FA03, - 0x6A90FA64, 0x6AA0FA55, 0x6AB01E3C, 0x6AC00159, 0x5B04FA54, 0x6AD01E40, 0x6AE000C3, 0x6AF01F2D, - 0x6B0C01EB, 0x6B1EF8CA, 0x6B300146, 0x6B401F85, 0x46F914, 0x6B6404D2, 0x6B78F9A9, 0x6B8AF8AD, - 0x3702F92D, 0x6B98F99A, 0x27A8038F, 0x6BA8F9E1, 0x6BBAF8A6, 0x1280FA00, 0x6BC80170, 0x6BD8F9B0, - 0x5E700390, 0x6BE8F9AB, 0x3034FA43, 0x6BF830B4, 0x6C14F935, 0x6C2422E0, 0x6C3C21CF, 0x6C56F997, - 0x6C6AF823, 0x6C781F06, 0x6C941E0C, 0x6CA41F8C, 0x6CCAF9A9, 0x6CDAF98D, 0x6CE8012A, 0x6CF81F15, - 0x6D14FB34, 0x6D281E7A, 0x6D40FB43, 0x6D54FABD, 0x6D66F978, 0x6D741E6A, 0x6D84FAC9, 0x6D9422EA, - 0x6DAC0157, 0x6DBC1E14, 0x6DD41E48, 0x6DE4232A, 0x6DF4FA8A, 0x6E041FA9, 0x6E201FDF, 0x6E381EB1, - 0x6E50FB35, 0x6E66F903, 0x6E74F958, 0x6E86F93D, 0x6E980232, 0x6EAAF99B, 0x6EB914BC, 0x6EDC1FD7, - 0x6EF80109, 0x6F08FA04, 0x6F18F9A2, 0x6F28F9C4, 0x6F381E61, 0x6F482288, 0x448803AC, 0x6F60FA7E, - 0x6F701ED1, 0x6F89D162, 0x6FBEF904, 0x6988F9BF, 0x6FCEF9B7, 0x6FDCF9EF, 0x6FEEF84A, 0x6FFC0B4C, - 0x701AF8CD, 0x70281FD0, 0x703EF8ED, 0x704C0B48, 0x7068F97B, 0x70781E2F, 0x70901E36, 0x70A0045D, - 0x70B4045E, 0x70C81ED3, 0x70E2F9B0, 0x70F401F5, 0x7104F9AC, 0x7116FA1C, 0x7124F910, 0x71340419, - 0x71481ECA, 0x71580A5E, 0x71740100, 0x718430F4, 0x71A01F74, 0x71B40172, 0x71C41F55, 0x71E2F85C, - 0x71F2F8D1, 0x7200F9C1, 0x7212F82E, 0x72201F30, 0x7236F840, 0x72441EBF, 0x725EF8AA, 0x726EF861, - 0x72801F18, 0x729401EE, 0x72A81E3E, 0x72B804D0, 0x72CC1EE9, 0x72E6F937, 0x72F801D3, 0x1D0FA77, - 0x7308F92F, 0x7318FA2B, 0x732AF8DE, 0x6988F95C, 0x7338FA18, 0x7348F9FC, 0x73581EB8, 0x73681F76, - 0x737CF968, 0x738C1EEC, 0x73A430BE, 0x73C01B41, 0x73DEF8A4, 0x73F2F8E0, 0x19E0FA3F, 0x740009DD, - 0x741C2280, 0x7434FAB9, 0x7444F941, 0x7456F969, 0x74641EA8, 0x747C0F9D, 0x74981E78, 0x74B030BC, - 0x74CCF94E, 0x74DEF9FB, 0x74F0FA0B, 0x7502F806, 0x75101E09, 0x7528F96D, 0x7538FA4F, 0x75481E5E, - 0x755830D3, 0x75742270, 0x758EF8DA, 0x759C1FB8, 0x75B01E0B, 0x75C0F93C, 0x75D01F51, 0x75E4FB44, - 0x75F8F92E, 0x760AF98E, 0x7619D1BB, 0x763EF942, 0x76501E3F, 0x766030C2, 0x767C01EA, 0x768EFA01, - 0x76A01E3D, 0x76B004D6, 0x76C6F92F, 0x76D4F906, 0x76E6F93A, 0x76F401D5, 0x770EF908, 0x771EF93F, - 0x772C0151, 0x773C1F57, 0x77581E43, 0x7768F980, 0x77781F69, 0x778CF9DA, 0x779C1F63, 0x77B80116, - 0x1486F97A, 0x77C81E6E, 0x77D830F8, 0x77F6F9A4, 0x78081FDD, 0x7820F97A, 0x5B2CFA47, 0x7832F87B, - 0x78442281, 0x785C1E11, 0x786C040C, 0x7882F8EB, 0x789000FA, 0x2304FA5E, 0x78A00204, 0x78B01F33, - 0x78CC00E1, 0x78DC1B3D, 0x78F830DA, 0x7916F97D, 0x79242000, 0x7934FB49, 0x7948F9C9, 0x5EE8FA87, - 0x795AF884, 0x7968FAA5, 0x797822AC, 0x799004EB, 0x79A41F80, 0x79C2F8F2, 0x79D01EF8, 0x79E2F852, - 0x79F2F9BF, 0x7A00F9DE, 0x7A12F8B0, 0x7A22F962, 0x7A32F996, 0x7A41D1BF, 0x7A7401A0, 0x7A8400ED, - 0x7A94FB3B, 0x7AA81F94, 0x7ACEF9CE, 0x7ADEF8D7, 0x7AEC2271, 0x7B04F957, 0x7B14F93E, 0x7B241EDB, - 0x7B3C1FB7, 0x7B5AF833, 0x7B681EAB, 0x7B800145, 0x7B92F9E8, 0x7BA1112F, 0x7BC41E31, 0x7BD41FF7, - 0x7BF01F32, 0x7C0C04EC, 0x7C2001CD, 0x7C301F0B, 0x7C4EF99E, 0x7C5EF899, 0x7C6C0158, 0x7C7C1EB4, - 0x7C940626, 0x7CA801EC, 0x7CC01F2B, 0x7CDCFA72, 0x7A10FA40, 0x7CEEF8FB, 0x7D02F8DC, 0x7D12F9D7, - 0x7D200959, 0x7D3C020A, 0x7D4C1F20, 0x7D62F81F, 0x7D7114BE, 0x7D96F8FD, 0x7B5AF831, 0x2BD6F805, - 0x3842F81B, 0x7DA41F92, 0x7DC91938, 0x7DEC1E5A, 0x625AF893, 0x7DFC0216, 0x7E0EF973, 0x7E200934, - 0x7E3C01DA, 0x7E54FAC6, 0x7E641F03, 0x7E82FA12, 0x7E941E8B, 0x7EA6FA06, 0x7EB4FA8C, 0x7EC4F9A4, - 0x163CF96F, 0x7ED41F87, 0x7EF804C1, 0x7F0EF99A, 0x7F1C1F3A, 0x7F3AF8F8, 0x7F4C1F05, 0x7F681F78, - 0x7F7C0FB9, 0x7F981E22, 0x7FA81FF2, 0x7FC6F979, 0x7FD6F909, 0x11041FBB, 0x7FE43067, 0x8000F9FD, - 0x80101F8B, 0x8034F945, 0x804404F1, 0x80580164, 0x80681E71, 0x807AF819, 0x80881FCE, 0x80A01FCC, - 0x80B41EC3, 0x80CCFAA3, 0x80DEF932, 0x80EC1E24, 0x80FCF96C, 0x810C022E, 0x811C1E2B, 0x812C0D4A, - 0x814801F8, 0x28ECF928, 0x8158FA2F, 0x81680F5C, 0x81843058, 0x81A01E2D, 0x81B0F934, 0x81C0F9D8, - 0x81D0F9C2, 0x81E2F9EF, 0x47AEF846, 0x81F0FA5A, 0x820030D6, 0x821C1F8D, 0x3A8C1FC9, 0x8242F9F6, - 0x8254F916, 0x8265D163, 0x50FEF8A7, 0x82981E1F, 0x82A81FD8, 0x82BC1FE5, 0x82D01F04, 0x82EC0340, - 0x57B8FA10, 0x82F8017D, 0x8309D1BE, 0x833C0CC7, 0x83581FA3, 0x837EF951, 0x838C1E7E, 0x839C1F8F, - 0x83C01EB5, 0x83DAF824, 0x83EAF91F, 0x83FC1ED0, 0x8414FAD0, 0x8428016D, 0xCD4FA76, 0x8438FA20, - 0x8448F98A, 0x84581E10, 0x84680115, 0x1484FA5B, 0x2A4EF902, 0x8478F912, 0x84880122, 0x849AF9A3, - 0x84AAF8A2, 0x84B830F9, 0x84D40FAC, 0x84F0F9C8, 0x8500F922, 0x85101E69, 0x8528014D, 0x85381F9B, - 0x855C1E21, 0x856CFB32, 0x85800177, 0x85901ED2, 0x85A80476, 0x85BC022B, 0x85D401D7, 0x85EC0219, - 0x85FC0228, 0x860C3062, 0x86281E56, 0x863804F2, 0x864EF963, 0x865C0DDC, 0x867AF91C, 0x86880450, - 0x869C1F38, 0x86B00229, 0x86C2FA00, 0x86D0FA1D, 0x12D0FA44, 0x86E00136, 0x86F0F965, 0x8700F9F2, - 0x53500389, 0x87103065, 0x7B5AF832, 0x872CF90E, 0x873EF8B8, 0x8752F82C, 0x8762F992, 0x87700107, - 0x4BE0212B, 0x3234FA92, 0x87802241, 0x8798095C, 0x87B4F905, 0x87C4F9A5, 0x87D6F95C, 0x87EAF8E3, - 0x87FC0CC0, 0x881801F4, 0x88281F65, 0x8846F967, 0x8856F8E1, 0x8864309E, 0x88800113, 0x8890020B, - 0x88A01FAB, 0x88C6F8D5, 0x266CFA69, 0x88D43079, 0x88F01F2F, 0x890C1EC8, 0x891CFB4B, 0x89300B5C, - 0x894EF817, 0x895C00FD, 0x896C040E, 0x89801E00, 0x8990017C, 0x89A0F94C, 0x1B94FA96, 0x89B01E44, - 0x89C01F7C, 0x89D4FB1D, 0x89E800F5, 0x89F8226E, 0x8A08F997, 0x8A181FB6, 0x8A2EF9BD, 0x8A3EF835, - 0x8A4EF867, 0x8A5CFA4A, 0x8A6CFA59, 0x8A7CF972, 0x8A8EF92A, 0x1B94F970, 0x8A9C1FE4, 0x8AB2F91D, - 0x8AC6F80F, 0x8AD40A33, 0x8AF01F4A, 0x8B0EF965, 0x8B201F0C, 0x2B2CF907, 0x8B3CF95A, 0x8B4C1ECE, - 0x559EF84C, 0x8B5C0F78, 0x8B780F76, 0x8B9400E0, 0x8BA40207, 0x8BB6F811, 0x8BC4F955, 0x8BD4F90B, - 0x8BE41E4E, 0x8BFC1FA2, 0x8C22F8C7, 0x8C301EB3, 0x8C48F903, 0x8C581E33, 0x8C681F10, 0x8C7EF80B, - 0x8C8C1E8A, 0x8C9CF902, 0x8CAD15BA, 0x8CD030FE, 0x8CEEF8E8, 0x8CFCFA8D, 0x4F20FA62, 0x8D0C04E7, - 0x8D20010E, 0x8D301EE5, 0x8D42F834, 0x2CEF8E7, 0x8D540175, 0x8D64F9B5, 0x7A10FA8B, 0x8D76F83A, - 0x8D840CCA, 0x8DA01F70, 0x8DB4FA08, 0x8DC6F9D4, 0x8DD40147, 0x8DE4FA9F, 0x4D40FA68, 0x8DF4F9EB, - 0x1188FA93, 0x8E06F9D9, 0x8E181EAD, 0x8E30FA39, 0x8E42F9C2, 0x8E52F9B1, 0x8E6422ED, 0x8E7EF83C, - 0x8E8C1EBD, 0x8E9CF901, 0x8EAEF917, 0x3830F95F, 0x8EBCFAD4, 0x8ECC00F4, 0x6D54F95D, 0x8EDEF970, - 0x8EEC0387, 0x3F4AF80E, 0x8EF81E05, 0x8F081FE8, 0x8EBEF949, 0x8F1EF8C1, 0x8F2EF954, 0x8F40F938, - 0x8F52F98F, 0x8F601E76, 0x8F72F886, 0x8F801F3D, 0x8F9C0129, 0x8FAC1E57, 0x8FBC0117, 0x8FCEF81E, - 0x8FDCF9C0, 0x8FEC1ECF, 0x8FFEF989, 0x9010FAC5, 0x570EF82B, 0x9020F9F4, 0x9032F9B5, 0x436CFACD, - 0x9042F9DC, 0x9050F913, 0x90601E87, 0x9072F8EE, 0x65301FDB, 0x9080016A, 0x9092FA02, 0x314FAC8, - 0x90A2F8E5, 0x90B0FA9D, 0x90C03056, 0x90DC0FA7, 0x90F81F00, 0x910C0215, 0x911CF97D, 0x912C2279, - 0x91441FC4, 0x91602244, 0x9178F930, 0x91881F50, 0x919CFAAF, 0x91AC1EF9, 0x91BC0209, 0x5A8EF9DF, - 0x179AF8A3, 0x91CCF949, 0x91DEF910, 0x91F01E5D, 0x9209D1BD, 0x923EF8B3, 0x924C0403, 0x926009DF, - 0x927DD15F, 0x92A2F97C, 0x92B4F9E9, 0x92C514BB, 0x92EAF9D8, 0x92FEF9F5, 0x930C01F9, 0x931C30DD, - 0x93380101, 0x934AF9AD, 0x935EF95A, 0x16681F7D, -}; - -#define NFC_COMP_LEVEL_COUNT 3 - -static const uint16_t _swift_stdlib_nfc_comp_sizes[3] = { - 0x40, 0x40, 0x40, -}; - -static const uint64_t _swift_stdlib_nfc_comp_keys0[1] = { - 0x92AE59250292839C, -}; - -static const uint64_t _swift_stdlib_nfc_comp_keys1[1] = { - 0xB0087D6521441206, -}; - -static const uint64_t _swift_stdlib_nfc_comp_keys2[1] = { - 0x500C890402981802, -}; - -static const uint64_t * const _swift_stdlib_nfc_comp_keys[3] = { - _swift_stdlib_nfc_comp_keys0, _swift_stdlib_nfc_comp_keys1, _swift_stdlib_nfc_comp_keys2, -}; - -static const uint16_t _swift_stdlib_nfc_comp_ranks0[1] = { - 0x0, -}; - -static const uint16_t _swift_stdlib_nfc_comp_ranks1[1] = { - 0x1A, -}; - -static const uint16_t _swift_stdlib_nfc_comp_ranks2[1] = { - 0x30, -}; - -static const uint16_t * const _swift_stdlib_nfc_comp_ranks[3] = { - _swift_stdlib_nfc_comp_ranks0, _swift_stdlib_nfc_comp_ranks1, _swift_stdlib_nfc_comp_ranks2, -}; - -static const uint32_t _swift_stdlib_nfc_comp0[15] = { - 0x1E0030F, 0x37E0041, 0x37E0045, 0x37E0049, 0x37A004F, 0x37C0052, 0x37E0055, 0x3400061, 0x3400065, - 0x3400069, 0x33C006F, 0x33E0072, 0x3400075, 0x40474, 0x40475, -}; - -static const uint32_t _swift_stdlib_nfc_comp1[4] = { - 0x8110BA, 0x31099, 0x3109B, 0xD10A5, -}; - -static const uint32_t _swift_stdlib_nfc_comp2[45] = { - 0x5A00304, 0x17E0041, 0x19A0045, 0x3BB20047, 0x1C20049, 0x1FA004F, 0x22A0055, 0x3B20059, - 0x1400061, 0x15C0065, 0x3B740067, 0x1840069, 0x1BC006F, 0x1EC0075, 0x3740079, 0x23400C4, - 0x23800C6, 0x2AE00D5, 0x2A800D6, 0x1F200DC, 0x1F600E4, 0x1FA00E6, 0x27000F5, 0x26A00F6, 0x1B400FC, - 0x401EA, 0x401EB, 0x808C0226, 0x808C0227, 0x4022E, 0x4022F, 0x38500391, 0x38800399, 0x388803A5, - 0x380003B1, 0x383003B9, 0x383803C5, 0x1940418, 0x1960423, 0x1560438, 0x1580443, 0x41E36, 0x41E37, - 0x41E5A, 0x41E5B, -}; - -static const uint32_t _swift_stdlib_nfc_comp3[2] = { - 0x400B3E, 0x80B47, -}; - -static const uint32_t _swift_stdlib_nfc_comp4[45] = { - 0x5A00338, 0x4464003C, 0x4446003D, 0x4462003E, 0x142190, 0x122192, 0x342194, 0x800621D0, - 0x800621D2, 0x800C21D4, 0x22203, 0x22208, 0x2220B, 0x22223, 0x22225, 0xA223C, 0x22243, 0x42245, - 0x22248, 0x40224D, 0x22261, 0x182264, 0x182265, 0x42272, 0x42273, 0x42276, 0x42277, 0xC227A, - 0xC227B, 0xC8227C, 0xC8227D, 0x42282, 0x42283, 0x42286, 0x42287, 0xA22291, 0xA22292, 0x1422A2, - 0xA22A8, 0xA22A9, 0x822AB, 0x7022B2, 0x7022B3, 0x7022B4, 0x7022B5, -}; - -static const uint32_t _swift_stdlib_nfc_comp5[2] = { - 0x400C56, 0x40C46, -}; - -static const uint32_t _swift_stdlib_nfc_comp6[2] = { - 0x4009BE, 0x809C7, -}; - -static const uint32_t _swift_stdlib_nfc_comp7[17] = { - 0x2200314, 0x36F00391, 0x37080395, 0x37240397, 0x37400399, 0x3754039F, 0x389603A1, 0x376803A5, - 0x378003A9, 0x36A003B1, 0x36B803B5, 0x36D403B7, 0x36F003B9, 0x370403BF, 0x384803C1, 0x371803C5, - 0x373003C9, -}; - -static const uint32_t _swift_stdlib_nfc_comp8[47] = { - 0x5E00307, 0x3CA0041, 0x3B800042, 0x18E0043, 0x3B8C0044, 0x1A20045, 0x3BB00046, 0x1B20047, - 0x3BB40048, 0x1CE0049, 0x3BE6004D, 0x3BEC004E, 0x3BE004F, 0x3C0C0050, 0x3C0C0052, 0x3C1A0053, - 0x3C2C0054, 0x3C5E0057, 0x3C640058, 0x3C6A0059, 0x242005A, 0x38C0061, 0x3B420062, 0x1500063, - 0x3B4E0064, 0x1640065, 0x3B720066, 0x1740067, 0x3B760068, 0x3BA8006D, 0x3BAE006E, 0x380006F, - 0x3BCE0070, 0x3BCE0072, 0x3BDC0073, 0x3BEE0074, 0x3C200077, 0x3C260078, 0x3C2C0079, 0x204007A, - 0x3A14015A, 0x3A14015B, 0x3A0C0160, 0x3A0C0161, 0x3A38017F, 0xC1E62, 0xC1E63, -}; - -static const uint32_t _swift_stdlib_nfc_comp9[5] = { - 0xA00326, 0x38A0053, 0x38C0054, 0x34C0073, 0x34E0074, -}; - -static const uint32_t _swift_stdlib_nfc_comp10[2] = { - 0x400CD6, 0x40CC6, -}; - -static const uint32_t _swift_stdlib_nfc_comp11[7] = { - 0xE00330, 0x3BAA0045, 0x3BC60049, 0x3C3E0055, 0x3B6C0065, 0x3B880069, 0x3C000075, -}; - -static const uint32_t _swift_stdlib_nfc_comp12[3] = { - 0x600DCA, 0x20DD9, 0x20DDC, -}; - -static const uint32_t _swift_stdlib_nfc_comp13[2] = { - 0x4114B0, 0x714B9, -}; - -static const uint32_t _swift_stdlib_nfc_comp14[3] = { - 0x611127, 0x80071131, 0x80071132, -}; - -static const uint32_t _swift_stdlib_nfc_comp15[2] = { - 0x400DDF, 0xA0DD9, -}; - -static const uint32_t _swift_stdlib_nfc_comp16[38] = { - 0x4C0030C, 0x3180041, 0x1920043, 0x1940044, 0x1AA0045, 0x33E0047, 0x3AC0048, 0x30C0049, 0x33A004B, - 0x1E2004C, 0x1F2004E, 0x304004F, 0x20C0052, 0x21A0053, 0x2200054, 0x2FC0055, 0x246005A, 0x2DA0061, - 0x1540063, 0x1560064, 0x16C0065, 0x3000067, 0x36E0068, 0x2CE0069, 0x30C006A, 0x2FC006B, 0x1A4006C, - 0x1B4006E, 0x2C6006F, 0x1CE0072, 0x1DC0073, 0x1E20074, 0x2BE0075, 0x208007A, 0x1FA00DC, 0x1BC00FC, - 0x6E01B7, 0x81460292, -}; - -static const uint32_t _swift_stdlib_nfc_comp17[64] = { - 0x8000345, 0x38560391, 0x386A0397, 0x38A603A9, 0x381003AC, 0x382C03AE, 0x380403B1, 0x381803B7, - 0x385403C9, 0x384C03CE, 0x1001F00, 0x1001F01, 0x1001F02, 0x1001F03, 0x1001F04, 0x1001F05, - 0x1001F06, 0x1001F07, 0x1001F08, 0x1001F09, 0x1001F0A, 0x1001F0B, 0x1001F0C, 0x1001F0D, 0x1001F0E, - 0x1001F0F, 0xE01F20, 0xE01F21, 0xE01F22, 0xE01F23, 0xE01F24, 0xE01F25, 0xE01F26, 0xE01F27, - 0xE01F28, 0xE01F29, 0xE01F2A, 0xE01F2B, 0xE01F2C, 0xE01F2D, 0xE01F2E, 0xE01F2F, 0x801F60, - 0x801F61, 0x801F62, 0x801F63, 0x801F64, 0x801F65, 0x801F66, 0x801F67, 0x801F68, 0x801F69, - 0x801F6A, 0x801F6B, 0x801F6C, 0x801F6D, 0x801F6E, 0x801F6F, 0x841F70, 0x9C1F74, 0xEC1F7C, 0x21FB6, - 0x21FC6, 0x21FF6, -}; - -static const uint32_t _swift_stdlib_nfc_comp18[5] = { - 0xA0031B, 0x2A2004F, 0x2B40055, 0x264006F, 0x2760075, -}; - -static const uint32_t _swift_stdlib_nfc_comp19[3] = { - 0x600BD7, 0x40B92, 0xC0BC6, -}; - -static const uint32_t _swift_stdlib_nfc_comp20[2] = { - 0x400CC2, 0x80CC6, -}; - -static const uint32_t _swift_stdlib_nfc_comp21[11] = { - 0x160309A, 0x4306F, 0x43072, 0x43075, 0x43078, 0x4307B, 0x430CF, 0x430D2, 0x430D5, 0x430D8, - 0x430DB, -}; - -static const uint32_t _swift_stdlib_nfc_comp22[85] = { - 0xAA00300, 0xFE0041, 0x1060045, 0x1060049, 0x354004E, 0x106004F, 0x1080055, 0x3C520057, - 0x3D320059, 0xFE0061, 0x1060065, 0x1060069, 0x316006E, 0x106006F, 0x1080075, 0x3C140077, - 0x3CF40079, 0x3E8A00A8, 0x3BC800C2, 0x3BEC00CA, 0x3BFC00D4, 0x1FE00DC, 0x3B8A00E2, 0x3BAE00EA, - 0x3BBE00F4, 0x1C000FC, 0x3B5C0102, 0x3B5C0103, 0x3A040112, 0x3A040113, 0x3A08014C, 0x3A08014D, - 0x3A7801A0, 0x3A7801A1, 0x3A7601AF, 0x3A7601B0, 0x38520391, 0x38660395, 0x38660397, 0x38820399, - 0x38B2039F, 0x388A03A5, 0x38A203A9, 0x377E03B1, 0x377A03B5, 0x377A03B7, 0x377A03B9, 0x377203BF, - 0x376A03C5, 0x376603C9, 0x381003CA, 0x382E03CB, 0x802A0415, 0x80160418, 0x360435, 0x4A0438, - 0x41F00, 0x41F01, 0x41F08, 0x41F09, 0x41F10, 0x41F11, 0x41F18, 0x41F19, 0x41F20, 0x41F21, 0x41F28, - 0x41F29, 0x41F30, 0x41F31, 0x41F38, 0x41F39, 0x41F40, 0x41F41, 0x41F48, 0x41F49, 0x41F50, 0x41F51, - 0x41F59, 0x41F60, 0x41F61, 0x41F68, 0x41F69, 0x1C1FBF, 0x80421FFE, -}; - -static const uint32_t _swift_stdlib_nfc_comp23[55] = { - 0x6E00308, 0x1060041, 0x10C0045, 0x3BBC0048, 0x10C0049, 0x10E004F, 0x10E0055, 0x3C5A0057, - 0x3C680058, 0x23E0059, 0x1060061, 0x10C0065, 0x3B7E0068, 0x10C0069, 0x10E006F, 0x3C460074, - 0x10E0075, 0x3C1C0077, 0x3C2A0078, 0x10C0079, 0x3AF200D5, 0x3AB400F5, 0x3A20016A, 0x3A20016B, - 0x220399, 0xC03A5, 0x2203B9, 0xC03C5, 0x403D2, 0x20406, 0x1840410, 0x80280415, 0x18C0416, - 0x18E0417, 0x1980418, 0x190041E, 0x19A0423, 0x19A0427, 0x19A042B, 0x17E042D, 0x1460430, 0x380435, - 0x14E0436, 0x1500437, 0x15A0438, 0x152043E, 0x15C0443, 0x15C0447, 0x15C044B, 0x140044D, 0x20456, - 0x404D8, 0x404D9, 0x404E8, 0x404E9, -}; - -static const uint32_t _swift_stdlib_nfc_comp24[2] = { - 0x4009D7, 0xA09C7, -}; - -static const uint32_t _swift_stdlib_nfc_comp25[30] = { - 0x3C00342, 0x3E3200A8, 0x380A03B1, 0x381E03B7, 0x383A03B9, 0x384203C5, 0x385A03C9, 0x381A03CA, - 0x383803CB, 0xC1F00, 0xC1F01, 0xC1F08, 0xC1F09, 0xC1F20, 0xC1F21, 0xC1F28, 0xC1F29, 0xC1F30, - 0xC1F31, 0xC1F38, 0xC1F39, 0xC1F50, 0xC1F51, 0xC1F59, 0xC1F60, 0xC1F61, 0xC1F68, 0xC1F69, - 0x201FBF, 0x803E1FFE, -}; - -static const uint32_t _swift_stdlib_nfc_comp26[3] = { - 0x6115AF, 0x515B8, 0x515B9, -}; - -static const uint32_t _swift_stdlib_nfc_comp27[2] = { - 0x400B56, 0x20B47, -}; - -static const uint32_t _swift_stdlib_nfc_comp28[49] = { - 0x6203099, 0x9C3046, 0x2304B, 0x2304D, 0x2304F, 0x23051, 0x23053, 0x23055, 0x23057, 0x23059, - 0x2305B, 0x2305D, 0x2305F, 0x23061, 0x23064, 0x23066, 0x23068, 0x2306F, 0x23072, 0x23075, 0x23078, - 0x2307B, 0x2309D, 0x9C30A6, 0x230AB, 0x230AD, 0x230AF, 0x230B1, 0x230B3, 0x230B5, 0x230B7, - 0x230B9, 0x230BB, 0x230BD, 0x230BF, 0x230C1, 0x230C4, 0x230C6, 0x230C8, 0x230CF, 0x230D2, 0x230D5, - 0x230D8, 0x230DB, 0x1030EF, 0x1030F0, 0x1030F1, 0x1030F2, 0x230FD, -}; - -static const uint32_t _swift_stdlib_nfc_comp29[3] = { - 0x60032E, 0x3BC40048, 0x3B860068, -}; - -static const uint32_t _swift_stdlib_nfc_comp30[2] = { - 0x400D57, 0xC0D46, -}; - -static const uint32_t _swift_stdlib_nfc_comp31[2] = { - 0x411930, 0x71935, -}; - -static const uint32_t _swift_stdlib_nfc_comp32[25] = { - 0x3200309, 0x3CC20041, 0x3CEA0045, 0x3CFE0049, 0x3CFE004F, 0x3D220055, 0x3D3A0059, 0x3C840061, - 0x3CAC0065, 0x3CC00069, 0x3CC0006F, 0x3CE40075, 0x3CFC0079, 0x3BCC00C2, 0x3BF000CA, 0x3C0000D4, - 0x3B8E00E2, 0x3BB200EA, 0x3BC200F4, 0x3B600102, 0x3B600103, 0x3A7C01A0, 0x3A7C01A1, 0x3A7A01AF, - 0x3A7A01B0, -}; - -static const uint32_t _swift_stdlib_nfc_comp33[2] = { - 0x40102E, 0x21025, -}; - -static const uint32_t _swift_stdlib_nfc_comp34[2] = { - 0x400653, 0x800A0627, -}; - -static const uint32_t _swift_stdlib_nfc_comp35[2] = { - 0x41133E, 0x91347, -}; - -static const uint32_t _swift_stdlib_nfc_comp36[23] = { - 0x2E00327, 0x1080043, 0x3B980044, 0x3C60045, 0x1B60047, 0x3BC00048, 0x1D6004B, 0x1DE004C, - 0x1EE004E, 0x2080052, 0x2160053, 0x21C0054, 0x1080063, 0x3B5A0064, 0x3880065, 0x1780067, - 0x3B820068, 0x198006B, 0x1A0006C, 0x1B0006E, 0x1CA0072, 0x1D80073, 0x1DE0074, -}; - -static const uint32_t _swift_stdlib_nfc_comp37[118] = { - 0xEC00301, 0x1000041, 0x1860043, 0x1080045, 0x35A0047, 0x1080049, 0x3BCA004B, 0x1DA004C, - 0x3BE2004D, 0x1EA004E, 0x108004F, 0x3C080050, 0x2040052, 0x20E0053, 0x10A0055, 0x3C560057, - 0x1080059, 0x23E005A, 0x1000061, 0x1480063, 0x1080065, 0x31C0067, 0x1080069, 0x3B8C006B, - 0x19C006C, 0x3BA4006D, 0x1AC006E, 0x108006F, 0x3BCA0070, 0x1C60072, 0x1D00073, 0x10A0075, - 0x3C180077, 0x1080079, 0x200007A, 0x5BA00A8, 0x3BC400C2, 0x26A00C5, 0x26C00C6, 0x3A8200C7, - 0x3BE800CA, 0x3ABE00CF, 0x3BF800D4, 0x3AEE00D5, 0x24C00D8, 0x1F600DC, 0x3B8600E2, 0x22C00E5, - 0x22E00E6, 0x3A4400E7, 0x3BAA00EA, 0x3A8000EF, 0x3BBA00F4, 0x3AB000F5, 0x20E00F8, 0x1B800FC, - 0x3B580102, 0x3B580103, 0x3A080112, 0x3A080113, 0x3A0C014C, 0x3A0C014D, 0x3A200168, 0x3A200169, - 0x3A7401A0, 0x3A7401A1, 0x3A7201AF, 0x3A7201B0, 0x80160391, 0x801A0395, 0x801C0397, 0x801E0399, - 0x8026039F, 0x802E03A5, 0x803403A9, 0x800A03B1, 0x801003B5, 0x801203B7, 0x801403B9, 0x1A03BF, - 0x1003C5, 0xA03C9, 0x807403CA, 0x803603CB, 0x203D2, 0x80200413, 0x801C041A, 0x400433, 0x44043A, - 0x81F00, 0x81F01, 0x81F08, 0x81F09, 0x81F10, 0x81F11, 0x81F18, 0x81F19, 0x81F20, 0x81F21, 0x81F28, - 0x81F29, 0x81F30, 0x81F31, 0x81F38, 0x81F39, 0x81F40, 0x81F41, 0x81F48, 0x81F49, 0x81F50, 0x81F51, - 0x81F59, 0x81F60, 0x81F61, 0x81F68, 0x81F69, 0x1E1FBF, 0x80401FFE, -}; - -static const uint32_t _swift_stdlib_nfc_comp38[29] = { - 0x3A00303, 0x1040041, 0x3CEE0045, 0x1BE0049, 0x106004E, 0x10C004F, 0x2260055, 0x3C4C0056, - 0x3D3E0059, 0x1040061, 0x3CB00065, 0x1800069, 0x106006E, 0x10C006F, 0x1E80075, 0x3C0E0076, - 0x3D000079, 0x3BD000C2, 0x3BF400CA, 0x3C0400D4, 0x3B9200E2, 0x3BB600EA, 0x3BC600F4, 0x3B640102, - 0x3B640103, 0x3A8001A0, 0x3A8001A1, 0x3A7E01AF, 0x3A7E01B0, -}; - -static const uint32_t _swift_stdlib_nfc_comp39[2] = { - 0x4114BA, 0x514B9, -}; - -static const uint32_t _swift_stdlib_nfc_comp40[2] = { - 0x4114BD, 0xB14B9, -}; - -static const uint32_t _swift_stdlib_nfc_comp41[7] = { - 0xE0030B, 0x202004F, 0x2360055, 0x1C4006F, 0x1F80075, 0x19E0423, 0x1600443, -}; - -static const uint32_t _swift_stdlib_nfc_comp42[2] = { - 0x400655, 0x80040627, -}; - -static const uint32_t _swift_stdlib_nfc_comp43[13] = { - 0x1A0032D, 0x3B9C0044, 0x3BA60045, 0x3BE0004C, 0x3BF8004E, 0x3C380054, 0x3C420055, 0x3B5E0064, - 0x3B680065, 0x3BA2006C, 0x3BBA006E, 0x3BFA0074, 0x3C040075, -}; - -static const uint32_t _swift_stdlib_nfc_comp44[33] = { - 0x4200306, 0x1820041, 0x19E0045, 0x1AE0047, 0x1C60049, 0x1FE004F, 0x22E0055, 0x1440061, 0x1600065, - 0x1700067, 0x1880069, 0x1C0006F, 0x1F00075, 0x37E80228, 0x37E80229, 0x384E0391, 0x387E0399, - 0x388603A5, 0x37FE03B1, 0x382E03B9, 0x383603C5, 0x1800410, 0x1820415, 0x1560416, 0x20418, - 0x802A0423, 0x1420430, 0x1440435, 0x1180436, 0x20438, 0x360443, 0x2C1EA0, 0x2C1EA1, -}; - -static const uint32_t _swift_stdlib_nfc_comp45[3] = { - 0x600324, 0x3C3A0055, 0x3BFC0075, -}; - -static const uint32_t _swift_stdlib_nfc_comp46[4] = { - 0x80093C, 0x20928, 0x20930, 0x20933, -}; - -static const uint32_t _swift_stdlib_nfc_comp47[2] = { - 0x400B57, 0xA0B47, -}; - -static const uint32_t _swift_stdlib_nfc_comp48[7] = { - 0xE00654, 0x80080627, 0x80480648, 0x8048064A, 0x206C1, 0x206D2, 0x802A06D5, -}; - -static const uint32_t _swift_stdlib_nfc_comp49[3] = { - 0x600BBE, 0x80BC6, 0x80BC7, -}; - -static const uint32_t _swift_stdlib_nfc_comp50[2] = { - 0x400DCF, 0x60DD9, -}; - -static const uint32_t _swift_stdlib_nfc_comp51[7] = { - 0xE0030A, 0x1080041, 0x2320055, 0x1080061, 0x1F40075, 0x3C420077, 0x3C400079, -}; - -static const uint32_t _swift_stdlib_nfc_comp52[13] = { - 0x1A00311, 0x3820041, 0x3820045, 0x3820049, 0x37E004F, 0x3800052, 0x3820055, 0x3440061, 0x3440065, - 0x3440069, 0x340006F, 0x3420072, 0x3440075, -}; - -static const uint32_t _swift_stdlib_nfc_comp53[15] = { - 0x1E00313, 0x36EE0391, 0x37060395, 0x37220397, 0x373E0399, 0x3752039F, 0x377E03A9, 0x369E03B1, - 0x36B603B5, 0x36D203B7, 0x36EE03B9, 0x370203BF, 0x384603C1, 0x371603C5, 0x372E03C9, -}; - -static const uint32_t _swift_stdlib_nfc_comp54[18] = { - 0x2400331, 0x3B880042, 0x3B940044, 0x3BD2004B, 0x3BDC004C, 0x3BF4004E, 0x3C180052, 0x3C340054, - 0x3C74005A, 0x3B4A0062, 0x3B560064, 0x3C5C0068, 0x3B94006B, 0x3B9E006C, 0x3BB6006E, 0x3BDA0072, - 0x3BF60074, 0x3C36007A, -}; - -static const uint32_t _swift_stdlib_nfc_comp55[43] = { - 0x5600323, 0x3CBE0041, 0x3B840042, 0x3B900044, 0x3CE60045, 0x3BB80048, 0x3D020049, 0x3BCE004B, - 0x3BD4004C, 0x3BEA004D, 0x3BF0004E, 0x3CFA004F, 0x3C100052, 0x3C1E0053, 0x3C300054, 0x3D1E0055, - 0x3C500056, 0x3C620057, 0x3D360059, 0x3C70005A, 0x3C800061, 0x3B460062, 0x3B520064, 0x3CA80065, - 0x3B7A0068, 0x3CC40069, 0x3B90006B, 0x3B96006C, 0x3BAC006D, 0x3BB2006E, 0x3CBC006F, 0x3BD20072, - 0x3BE00073, 0x3BF20074, 0x3CE00075, 0x3C120076, 0x3C240077, 0x3CF80079, 0x3C32007A, 0x3A8401A0, - 0x3A8401A1, 0x3A8201AF, 0x3A8201B0, -}; - -static const uint32_t _swift_stdlib_nfc_comp56[12] = { - 0x1801B35, 0x21B05, 0x21B07, 0x21B09, 0x21B0B, 0x21B0D, 0x21B11, 0x21B3A, 0x21B3C, 0x41B3E, - 0x41B3F, 0x21B42, -}; - -static const uint32_t _swift_stdlib_nfc_comp57[11] = { - 0x1600328, 0x1860041, 0x1A60045, 0x1CA0049, 0x336004F, 0x23A0055, 0x1480061, 0x1680065, 0x18C0069, - 0x2F8006F, 0x1FC0075, -}; - -static const uint32_t _swift_stdlib_nfc_comp58[33] = { - 0x4200302, 0x1020041, 0x18A0043, 0x10A0045, 0x1AA0047, 0x1B80048, 0x10A0049, 0x1D4004A, 0x10A004F, - 0x2120053, 0x10C0055, 0x23A0057, 0x23A0059, 0x3C6C005A, 0x1020061, 0x14C0063, 0x10A0065, - 0x16C0067, 0x17A0068, 0x10A0069, 0x196006A, 0x10A006F, 0x1D40073, 0x10C0075, 0x1FC0077, 0x1FC0079, - 0x3C2E007A, 0x181EA0, 0x181EA1, 0x1C1EB8, 0x1C1EB9, 0x181ECC, 0x181ECD, -}; - -static const uint32_t _swift_stdlib_nfc_comp59[3] = { - 0x600D3E, 0x80D46, 0x80D47, -}; - -static const uint32_t _swift_stdlib_nfc_comp60[2] = { - 0x411357, 0xB1347, -}; - -static const uint32_t _swift_stdlib_nfc_comp61[4] = { - 0x800CD5, 0x20CBF, 0x20CC6, 0x20CCA, -}; - -static const uint32_t _swift_stdlib_nfc_comp62[3] = { - 0x600325, 0x3B7E0041, 0x3B400061, -}; - -static const uint32_t * const _swift_stdlib_nfc_comp_indices[63] = { - _swift_stdlib_nfc_comp0, _swift_stdlib_nfc_comp1, _swift_stdlib_nfc_comp2, - _swift_stdlib_nfc_comp3, _swift_stdlib_nfc_comp4, _swift_stdlib_nfc_comp5, - _swift_stdlib_nfc_comp6, _swift_stdlib_nfc_comp7, _swift_stdlib_nfc_comp8, - _swift_stdlib_nfc_comp9, _swift_stdlib_nfc_comp10, _swift_stdlib_nfc_comp11, - _swift_stdlib_nfc_comp12, _swift_stdlib_nfc_comp13, _swift_stdlib_nfc_comp14, - _swift_stdlib_nfc_comp15, _swift_stdlib_nfc_comp16, _swift_stdlib_nfc_comp17, - _swift_stdlib_nfc_comp18, _swift_stdlib_nfc_comp19, _swift_stdlib_nfc_comp20, - _swift_stdlib_nfc_comp21, _swift_stdlib_nfc_comp22, _swift_stdlib_nfc_comp23, - _swift_stdlib_nfc_comp24, _swift_stdlib_nfc_comp25, _swift_stdlib_nfc_comp26, - _swift_stdlib_nfc_comp27, _swift_stdlib_nfc_comp28, _swift_stdlib_nfc_comp29, - _swift_stdlib_nfc_comp30, _swift_stdlib_nfc_comp31, _swift_stdlib_nfc_comp32, - _swift_stdlib_nfc_comp33, _swift_stdlib_nfc_comp34, _swift_stdlib_nfc_comp35, - _swift_stdlib_nfc_comp36, _swift_stdlib_nfc_comp37, _swift_stdlib_nfc_comp38, - _swift_stdlib_nfc_comp39, _swift_stdlib_nfc_comp40, _swift_stdlib_nfc_comp41, - _swift_stdlib_nfc_comp42, _swift_stdlib_nfc_comp43, _swift_stdlib_nfc_comp44, - _swift_stdlib_nfc_comp45, _swift_stdlib_nfc_comp46, _swift_stdlib_nfc_comp47, - _swift_stdlib_nfc_comp48, _swift_stdlib_nfc_comp49, _swift_stdlib_nfc_comp50, - _swift_stdlib_nfc_comp51, _swift_stdlib_nfc_comp52, _swift_stdlib_nfc_comp53, - _swift_stdlib_nfc_comp54, _swift_stdlib_nfc_comp55, _swift_stdlib_nfc_comp56, - _swift_stdlib_nfc_comp57, _swift_stdlib_nfc_comp58, _swift_stdlib_nfc_comp59, - _swift_stdlib_nfc_comp60, _swift_stdlib_nfc_comp61, _swift_stdlib_nfc_comp62, -}; - -#endif // #ifndef NORMALIZATION_DATA_H diff --git a/Sources/_CUnicode/Common/GraphemeData.h b/Sources/_CUnicode/Common/GraphemeData.h deleted file mode 100644 index 053f4ee29..000000000 --- a/Sources/_CUnicode/Common/GraphemeData.h +++ /dev/null @@ -1,141 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -// This was auto-generated by utils/gen-unicode-data/GenGraphemeBreakProperty, -// please do not edit this file yourself! - -#ifndef GRAPHEME_DATA_H -#define GRAPHEME_DATA_H - -#include "stdint.h" - -#define GRAPHEME_BREAK_DATA_COUNT 621 - -static const uint32_t _swift_stdlib_graphemeBreakProperties[621] = { - 0x3E00000, 0x400007F, 0x800000A9, 0xAD, 0x800000AE, 0x2DE00300, 0x20C00483, 0x25800591, - 0x200005BF, 0x202005C1, 0x202005C4, 0x200005C7, 0x40A00600, 0x21400610, 0x61C, 0x2280064B, - 0x20000670, 0x20C006D6, 0x400006DD, 0x20A006DF, 0x202006E7, 0x206006EA, 0x4000070F, 0x20000711, - 0x23400730, 0x214007A6, 0x210007EB, 0x200007FD, 0x20600816, 0x2100081B, 0x20400825, 0x20800829, - 0x20400859, 0x40200890, 0x20E00898, 0x22E008CA, 0x400008E2, 0x23E008E3, 0x60000903, 0x2000093A, - 0x6000093B, 0x2000093C, 0x6040093E, 0x20E00941, 0x60600949, 0x2000094D, 0x6020094E, 0x20C00951, - 0x20200962, 0x20000981, 0x60200982, 0x200009BC, 0x200009BE, 0x602009BF, 0x206009C1, 0x602009C7, - 0x602009CB, 0x200009CD, 0x200009D7, 0x202009E2, 0x200009FE, 0x20200A01, 0x60000A03, 0x20000A3C, - 0x60400A3E, 0x20200A41, 0x20200A47, 0x20400A4B, 0x20000A51, 0x20200A70, 0x20000A75, 0x20200A81, - 0x60000A83, 0x20000ABC, 0x60400ABE, 0x20800AC1, 0x20200AC7, 0x60000AC9, 0x60200ACB, 0x20000ACD, - 0x20200AE2, 0x20A00AFA, 0x20000B01, 0x60200B02, 0x20000B3C, 0x20200B3E, 0x60000B40, 0x20600B41, - 0x60200B47, 0x60200B4B, 0x20000B4D, 0x20400B55, 0x20200B62, 0x20000B82, 0x20000BBE, 0x60000BBF, - 0x20000BC0, 0x60200BC1, 0x60400BC6, 0x60400BCA, 0x20000BCD, 0x20000BD7, 0x20000C00, 0x60400C01, - 0x20000C04, 0x20000C3C, 0x20400C3E, 0x60600C41, 0x20400C46, 0x20600C4A, 0x20200C55, 0x20200C62, - 0x20000C81, 0x60200C82, 0x20000CBC, 0x60000CBE, 0x20000CBF, 0x60200CC0, 0x20000CC2, 0x60200CC3, - 0x20000CC6, 0x60200CC7, 0x60200CCA, 0x20200CCC, 0x20200CD5, 0x20200CE2, 0x20200D00, 0x60200D02, - 0x20200D3B, 0x20000D3E, 0x60200D3F, 0x20600D41, 0x60400D46, 0x60400D4A, 0x20000D4D, 0x40000D4E, - 0x20000D57, 0x20200D62, 0x20000D81, 0x60200D82, 0x20000DCA, 0x20000DCF, 0x60200DD0, 0x20400DD2, - 0x20000DD6, 0x60C00DD8, 0x20000DDF, 0x60200DF2, 0x20000E31, 0x60000E33, 0x20C00E34, 0x20E00E47, - 0x20000EB1, 0x60000EB3, 0x21000EB4, 0x20A00EC8, 0x20200F18, 0x20000F35, 0x20000F37, 0x20000F39, - 0x60200F3E, 0x21A00F71, 0x60000F7F, 0x20800F80, 0x20200F86, 0x21400F8D, 0x24600F99, 0x20000FC6, - 0x2060102D, 0x60001031, 0x20A01032, 0x20201039, 0x6020103B, 0x2020103D, 0x60201056, 0x20201058, - 0x2040105E, 0x20601071, 0x20001082, 0x60001084, 0x20201085, 0x2000108D, 0x2000109D, 0x2040135D, - 0x20401712, 0x60001715, 0x20201732, 0x60001734, 0x20201752, 0x20201772, 0x202017B4, 0x600017B6, - 0x20C017B7, 0x60E017BE, 0x200017C6, 0x602017C7, 0x214017C9, 0x200017DD, 0x2040180B, 0x180E, - 0x2000180F, 0x20201885, 0x200018A9, 0x20401920, 0x60601923, 0x20201927, 0x60401929, 0x60201930, - 0x20001932, 0x60A01933, 0x20401939, 0x20201A17, 0x60201A19, 0x20001A1B, 0x60001A55, 0x20001A56, - 0x60001A57, 0x20C01A58, 0x20001A60, 0x20001A62, 0x20E01A65, 0x60A01A6D, 0x21201A73, 0x20001A7F, - 0x23C01AB0, 0x20601B00, 0x60001B04, 0x20C01B34, 0x60001B3B, 0x20001B3C, 0x60801B3D, 0x20001B42, - 0x60201B43, 0x21001B6B, 0x20201B80, 0x60001B82, 0x60001BA1, 0x20601BA2, 0x60201BA6, 0x20201BA8, - 0x60001BAA, 0x20401BAB, 0x20001BE6, 0x60001BE7, 0x20201BE8, 0x60401BEA, 0x20001BED, 0x60001BEE, - 0x20401BEF, 0x60201BF2, 0x60E01C24, 0x20E01C2C, 0x60201C34, 0x20201C36, 0x20401CD0, 0x21801CD4, - 0x60001CE1, 0x20C01CE2, 0x20001CED, 0x20001CF4, 0x60001CF7, 0x20201CF8, 0x27E01DC0, 0x200B, - 0x2000200C, 0x20200E, 0xC02028, 0x8000203C, 0x80002049, 0x1E02060, 0x240020D0, 0x80002122, - 0x80002139, 0x80A02194, 0x802021A9, 0x8020231A, 0x80002328, 0x80002388, 0x800023CF, 0x814023E9, - 0x804023F8, 0x800024C2, 0x802025AA, 0x800025B6, 0x800025C0, 0x806025FB, 0x80A02600, 0x81602607, - 0x8E202614, 0x8EA02690, 0x81402708, 0x80002714, 0x80002716, 0x8000271D, 0x80002721, 0x80002728, - 0x80202733, 0x80002744, 0x80002747, 0x8000274C, 0x8000274E, 0x80402753, 0x80002757, 0x80802763, - 0x80402795, 0x800027A1, 0x800027B0, 0x800027BF, 0x80202934, 0x80402B05, 0x80202B1B, 0x80002B50, - 0x80002B55, 0x20402CEF, 0x20002D7F, 0x23E02DE0, 0x20A0302A, 0x80003030, 0x8000303D, 0x20203099, - 0x80003297, 0x80003299, 0x2060A66F, 0x2120A674, 0x2020A69E, 0x2020A6F0, 0x2000A802, 0x2000A806, - 0x2000A80B, 0x6020A823, 0x2020A825, 0x6000A827, 0x2000A82C, 0x6020A880, 0x61E0A8B4, 0x2020A8C4, - 0x2220A8E0, 0x2000A8FF, 0x20E0A926, 0x2140A947, 0x6020A952, 0x2040A980, 0x6000A983, 0x2000A9B3, - 0x6020A9B4, 0x2060A9B6, 0x6020A9BA, 0x2020A9BC, 0x6040A9BE, 0x2000A9E5, 0x20A0AA29, 0x6020AA2F, - 0x2020AA31, 0x6020AA33, 0x2020AA35, 0x2000AA43, 0x2000AA4C, 0x6000AA4D, 0x2000AA7C, 0x2000AAB0, - 0x2040AAB2, 0x2020AAB7, 0x2020AABE, 0x2000AAC1, 0x6000AAEB, 0x2020AAEC, 0x6020AAEE, 0x6000AAF5, - 0x2000AAF6, 0x6020ABE3, 0x2000ABE5, 0x6020ABE6, 0x2000ABE8, 0x6020ABE9, 0x6000ABEC, 0x2000ABED, - 0x2000FB1E, 0x21E0FE00, 0x21E0FE20, 0xFEFF, 0x2020FF9E, 0x160FFF0, 0x200101FD, 0x200102E0, - 0x20810376, 0x20410A01, 0x20210A05, 0x20610A0C, 0x20410A38, 0x20010A3F, 0x20210AE5, 0x20610D24, - 0x20210EAB, 0x21410F46, 0x20610F82, 0x60011000, 0x20011001, 0x60011002, 0x21C11038, 0x20011070, - 0x20211073, 0x2041107F, 0x60011082, 0x604110B0, 0x206110B3, 0x602110B7, 0x202110B9, 0x400110BD, - 0x200110C2, 0x400110CD, 0x20411100, 0x20811127, 0x6001112C, 0x20E1112D, 0x60211145, 0x20011173, - 0x20211180, 0x60011182, 0x604111B3, 0x210111B6, 0x602111BF, 0x402111C2, 0x206111C9, 0x600111CE, - 0x200111CF, 0x6041122C, 0x2041122F, 0x60211232, 0x20011234, 0x60011235, 0x20211236, 0x2001123E, - 0x200112DF, 0x604112E0, 0x20E112E3, 0x20211300, 0x60211302, 0x2021133B, 0x2001133E, 0x6001133F, - 0x20011340, 0x60611341, 0x60211347, 0x6041134B, 0x20011357, 0x60211362, 0x20C11366, 0x20811370, - 0x60411435, 0x20E11438, 0x60211440, 0x20411442, 0x60011445, 0x20011446, 0x2001145E, 0x200114B0, - 0x602114B1, 0x20A114B3, 0x600114B9, 0x200114BA, 0x602114BB, 0x200114BD, 0x600114BE, 0x202114BF, - 0x600114C1, 0x202114C2, 0x200115AF, 0x602115B0, 0x206115B2, 0x606115B8, 0x202115BC, 0x600115BE, - 0x202115BF, 0x202115DC, 0x60411630, 0x20E11633, 0x6021163B, 0x2001163D, 0x6001163E, 0x2021163F, - 0x200116AB, 0x600116AC, 0x200116AD, 0x602116AE, 0x20A116B0, 0x600116B6, 0x200116B7, 0x2041171D, - 0x20611722, 0x60011726, 0x20811727, 0x6041182C, 0x2101182F, 0x60011838, 0x20211839, 0x20011930, - 0x60811931, 0x60211937, 0x2021193B, 0x6001193D, 0x2001193E, 0x4001193F, 0x60011940, 0x40011941, - 0x60011942, 0x20011943, 0x604119D1, 0x206119D4, 0x202119DA, 0x606119DC, 0x200119E0, 0x600119E4, - 0x21211A01, 0x20A11A33, 0x60011A39, 0x40011A3A, 0x20611A3B, 0x20011A47, 0x20A11A51, 0x60211A57, - 0x20411A59, 0x40A11A84, 0x21811A8A, 0x60011A97, 0x20211A98, 0x60011C2F, 0x20C11C30, 0x20A11C38, - 0x60011C3E, 0x20011C3F, 0x22A11C92, 0x60011CA9, 0x20C11CAA, 0x60011CB1, 0x20211CB2, 0x60011CB4, - 0x20211CB5, 0x20A11D31, 0x20011D3A, 0x20211D3C, 0x20C11D3F, 0x40011D46, 0x20011D47, 0x60811D8A, - 0x20211D90, 0x60211D93, 0x20011D95, 0x60011D96, 0x20011D97, 0x20211EF3, 0x60211EF5, 0x1013430, - 0x20816AF0, 0x20C16B30, 0x20016F4F, 0x66C16F51, 0x20616F8F, 0x20016FE4, 0x60216FF0, 0x2021BC9D, - 0x61BCA0, 0x25A1CF00, 0x22C1CF30, 0x2001D165, 0x6001D166, 0x2041D167, 0x6001D16D, 0x2081D16E, - 0xE1D173, 0x20E1D17B, 0x20C1D185, 0x2061D1AA, 0x2041D242, 0x26C1DA00, 0x2621DA3B, 0x2001DA75, - 0x2001DA84, 0x2081DA9B, 0x21C1DAA1, 0x20C1E000, 0x2201E008, 0x20C1E01B, 0x2021E023, 0x2081E026, - 0x20C1E130, 0x2001E2AE, 0x2061E2EC, 0x20C1E8D0, 0x20C1E944, 0x9FE1F000, 0x8041F10D, 0x8001F12F, - 0x80A1F16C, 0x8021F17E, 0x8001F18E, 0x8121F191, 0x8701F1AD, 0x81C1F201, 0x8001F21A, 0x8001F22F, - 0x8101F232, 0x8061F23C, 0xB621F249, 0x2081F3FB, 0xA7A1F400, 0xA121F546, 0x8FE1F680, 0x8161F774, - 0x8541F7D5, 0x8061F80C, 0x80E1F848, 0x80A1F85A, 0x80E1F888, 0x8A21F8AE, 0x85C1F90C, 0x8121F93C, - 0xB701F947, 0x3EE0000, 0x2BEE0020, 0xFEE0080, 0x3DEE0100, -}; - -static const uint16_t _swift_stdlib_linkingConsonant_ranks[165] = { - 0x0, 0xE, 0xE, 0x12, 0x13, 0x0, 0x0, 0x0, 0x25, 0x35, 0x0, 0x20, 0x25, 0x46, 0x4B, 0x0, 0x17, - 0x23, 0x3D, 0x44, 0x0, 0xA, 0x24, 0x31, 0x4B, 0x0, 0x1, 0x27, 0x27, 0x49, 0x0, 0xF, 0x2E, 0x3A, - 0x57, 0x0, 0x0, 0x1F, 0x2C, 0x2C, 0x0, 0x21, 0x2D, 0x3C, 0x3C, 0x0, 0x0, 0x0, 0xD, 0x2C, 0x0, - 0x2D, 0x30, 0x30, 0x30, 0x0, 0x0, 0x0, 0x1E, 0x31, 0x0, 0x2C, 0x2C, 0x63, 0x72, 0x0, 0x0, 0x0, - 0x29, 0x2F, 0x0, 0x26, 0x4A, 0x51, 0x51, 0x0, 0x18, 0x39, 0x54, 0x68, 0x0, 0x18, 0x2F, 0x53, 0x64, - 0x0, 0x23, 0x39, 0x69, 0x72, 0x0, 0x0, 0x0, 0xE, 0x18, 0x0, 0x0, 0xF, 0x25, 0x25, 0x0, 0x25, 0x26, - 0x49, 0x49, 0x0, 0x19, 0x37, 0x59, 0x61, 0x0, 0xC, 0x24, 0x52, 0x5D, 0x0, 0x8, 0x8, 0x8, 0x2A, - 0x0, 0x0, 0x21, 0x21, 0x21, 0x0, 0x2, 0x21, 0x23, 0x43, 0x0, 0x16, 0x22, 0x3D, 0x44, 0x0, 0x0, - 0x0, 0x22, 0x22, 0x0, 0x0, 0x0, 0x22, 0x22, 0x0, 0x22, 0x28, 0x4B, 0x73, 0x0, 0x0, 0x21, 0x21, - 0x3F, 0x0, 0x0, 0x25, 0x39, 0x43, 0x0, 0x12, 0x12, 0x12, 0x12, -}; - -static const uint64_t _swift_stdlib_linkingConsonant[166] = { - 0x5, 0x7E0FF00, 0x0, 0x3C0000000, 0x400000000000000, 0x5BFF, 0x0, 0x0, 0x3FFFFFFFFE00000, - 0xFF000000FF000000, 0x0, 0x3C5FDFFFFE0, 0x30000B000, 0x36DFDFFFFE0, 0x5E00, 0xFFE0, 0x3EDFDFF, - 0xFFE0000002000000, 0xB000000003EDFDFF, 0xD620000000020000, 0xC718, 0x3FF, 0xFDFFFFE000000000, - 0x700000003FF, 0xFDFFFFE000000000, 0x3EF, 0x40000000, 0x7FFFFFFFFE00000, 0x0, 0x2FFBFFFFFC000000, - 0x7F, 0xFFFE000000000000, 0x7FFFFFFF, 0xF7D6000000000000, 0x7FAFFFFF, 0xF000, 0x0, - 0xFFFFFEFF00000000, 0x1FFF, 0x0, 0x0, 0x1FFFFFFFF0000, 0xC0623C0300008000, 0x4003FFE1, 0x0, 0x0, - 0x0, 0x0, 0xFFF8000000000000, 0xFFF80003FFF88003, 0x3, 0xFFFFFFFF0001DFF8, 0x7, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7FFFFFFE0000, 0x7FFFF00000000, 0x0, 0xFFFFFFFFFFF, 0x0, 0xFFFFFFFF007FFFFF, 0x181FFF, - 0x0, 0x0, 0x0, 0x1FE0000FFFFFFFF8, 0xFC00000000000000, 0xFFFF, 0xFFFFFFFF3800C001, - 0xFFFFFFFF0000000F, 0xE0000000000F, 0x0, 0x0, 0xFFFFF78000000000, 0x3FFFFFFF00000007, - 0xFFFC00000005FE3C, 0xFFFFF, 0x0, 0x3FFFFFC000000, 0x7FFFFF, 0xFFFFFFFF8E000000, - 0xFF9F000000000007, 0x7C00, 0x1FFFFFFFFC0, 0xC40EFFFF00000000, 0xFFFFFFFFFFFF, 0x7FC00000000, 0x0, - 0x0, 0x0, 0x3FFF000000000000, 0x7FD, 0x0, 0x0, 0xFEEF000100000000, 0x3FFFFF, 0x0, 0x0, - 0xFFFFFFFFF80000, 0x20000000000000, 0xFFFFFFFFE000, 0x0, 0xFF80, 0x900000007FFFFF, 0x7FFFFFFE0, - 0x7FFFFFFFE, 0xFF00000000000000, 0xFFFB, 0xFFF, 0xBFFFBD7000000000, 0x7FFFFFFFFC0001FF, - 0xFFE0000000000000, 0xFDFF, 0x3ED, 0x0, 0x0, 0xFFFFFFFFC0000000, 0x1F, 0x0, 0xFFFFFFFF8000, 0x0, - 0x0, 0x0, 0xC000000000000000, 0x7FFFFFFF, 0xC000000000000000, 0xFFFFFFFF, 0x0, 0xFFFFFC0000000000, - 0x10007FF, 0x7FFFFFF00000000, 0x7F00000000, 0x0, 0x0, 0x0, 0xFFFFFFFFC000000, 0x0, 0x0, 0x0, 0x0, - 0xFFFFFF6FF000, 0x0, 0x0, 0xFFFFFFFFC0000000, 0xF800000000000001, 0x7FFFFFFFF, 0xFFFFFFFFFF000, - 0x0, 0x0, 0x7FFFFFFFC0000000, 0x0, 0xFFFFFFFC, 0x0, 0x0, 0x1FFFFFFFFF000, 0xFFFFF00000000000, - 0x3FF, 0x0, 0x3FFFF, 0x0, 0x0, 0x0, 0x0, -}; - -#endif // #ifndef GRAPHEME_DATA_H diff --git a/Sources/_CUnicode/Common/NormalizationData.h b/Sources/_CUnicode/Common/NormalizationData.h deleted file mode 100644 index 09a9b802c..000000000 --- a/Sources/_CUnicode/Common/NormalizationData.h +++ /dev/null @@ -1,1985 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -// This was auto-generated by utils/gen-unicode-data/GenNormalization, -// please do not edit this file yourself! - -#ifndef NORMALIZATION_DATA_H -#define NORMALIZATION_DATA_H - -#include "stdint.h" - -static const uint16_t _swift_stdlib_normData_data[66] = { - 0x110, 0x70, 0x3B0, 0x8, 0x750, 0x78, 0x6C4, 0x410, 0x6E0, 0x60, 0x734, 0x784, - 0x120, 0x3, 0x3D0, 0xD8, 0x4, 0xB8, 0x700, 0x44, 0xC, 0xA8, 0x80, 0x6F0, 0x1, - 0x740, 0x58, 0x650, 0x30, 0x338, 0x50, 0x48, 0x720, 0xD0, 0x654, 0xE0, 0x420, - 0x118, 0xC0, 0x748, 0x733, 0x2DC, 0x710, 0xB0, 0x6B0, 0x3C, 0x6E4, 0xF0, 0x90, - 0xE8, 0x358, 0x98, 0x108, 0x38, 0x100, 0x2A0, 0x88, 0x4C, 0x408, 0x730, 0x6D0, - 0x6C0, 0xF8, 0xC8, 0x68, 0xA0, -}; - -static const uint8_t _swift_stdlib_normData_data_indices[3041] = { - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0xA, 0xA, 0xA, 0xA, 0xA, 0x3B, 0xA, 0xA, 0xA, - 0xA, 0xA, 0xA, 0xA, 0x3B, 0x3B, 0xA, 0x3B, 0xA, 0x3B, 0xA, 0xA, 0x19, 0x8, - 0x8, 0x8, 0x8, 0x19, 0x6, 0x8, 0x8, 0x8, 0x8, 0x8, 0x1B, 0x1B, 0x2E, 0x2E, - 0x2E, 0x2E, 0x22, 0x22, 0x8, 0x8, 0x8, 0x8, 0x2E, 0x2E, 0x8, 0x2E, 0x2E, 0x8, - 0x8, 0x3, 0x3, 0x3, 0x3, 0x14, 0x8, 0x8, 0x8, 0x8, 0x3B, 0x3B, 0x3B, 0x28, - 0x28, 0xA, 0x28, 0x28, 0xB, 0x3B, 0x8, 0x8, 0x8, 0x3B, 0x3B, 0x3B, 0x8, 0x8, - 0x3B, 0x3B, 0x3B, 0x8, 0x8, 0x8, 0x8, 0x3B, 0x19, 0x8, 0x8, 0x3B, 0x27, 0x4, - 0x4, 0x27, 0x4, 0x4, 0x27, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0xD, 0xD, 0x18, 0x18, 0xD, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x8, 0x3B, 0x3B, - 0x3B, 0x3B, 0x8, 0x3B, 0x3B, 0x3B, 0x17, 0x8, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x3B, 0x3B, 0x8, 0x3B, 0x3B, 0x17, 0x20, - 0x3B, 0x1E, 0x1A, 0x9, 0x40, 0x1, 0x5, 0x16, 0x38, 0x30, 0x33, 0x33, 0x41, - 0x15, 0x2B, 0x11, 0x26, 0x3F, 0x3B, 0x8, 0x30, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x2F, 0x3E, 0x36, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF, 0x23, - 0x31, 0x2F, 0x3E, 0x36, 0x34, 0x0, 0xA, 0xA, 0x2E, 0x8, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x8, 0x3B, 0x3B, 0x8, 0x25, 0x18, 0x18, 0x18, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x8, 0x3B, 0x3B, 0x3B, 0x8, - 0x3B, 0x3B, 0x8, 0xC, 0x3B, 0x8, 0x3B, 0x3B, 0x8, 0x3B, 0x3B, 0x8, 0x8, 0x8, - 0x3B, 0x8, 0x8, 0x3B, 0x8, 0x3B, 0x3B, 0x3B, 0x8, 0x3B, 0x8, 0x3B, 0x8, 0x3B, - 0x8, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x8, 0x3B, 0x8, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x8, 0x8, 0x8, 0x3B, 0x8, 0x8, - 0x8, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x8, 0x8, 0x8, 0x8, - 0x8, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x8, 0x3B, 0x3B, 0x8, 0x3B, 0x3B, 0x8, 0x3B, 0x3B, 0x3B, 0x8, 0x8, - 0x8, 0xF, 0x23, 0x31, 0x3B, 0x3B, 0x3B, 0x8, 0x3B, 0x3B, 0x8, 0x8, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x18, 0x18, 0x18, 0x2D, 0x1F, 0x3B, 0x8, 0x3B, 0x3B, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0x35, 0x10, 0x18, 0x18, 0x1F, 0x10, 0xD, - 0xD, 0xD, 0x3B, 0xD, 0xD, 0x35, 0x1F, 0xD, 0xD, 0xD, 0xD, 0x35, 0x1F, 0x35, - 0x10, 0x18, 0x18, 0x18, 0x1F, 0x10, 0x10, 0xD, 0xD, 0x18, 0x10, 0x18, 0x18, - 0x18, 0x1F, 0x10, 0x35, 0x18, 0x1F, 0x37, 0x29, 0x35, 0x18, 0x10, 0x18, 0x18, - 0x18, 0x18, 0x1F, 0x10, 0x10, 0x1F, 0x1F, 0x10, 0x18, 0x18, 0x18, 0x1F, 0x10, - 0x39, 0x10, 0x18, 0x18, 0x18, 0x18, 0x10, 0x1D, 0x1D, 0x1F, 0x32, 0x32, 0x32, - 0x32, 0x2, 0x2, 0x1F, 0xE, 0xE, 0xE, 0xE, 0x8, 0x8, 0x8, 0x8, 0x3D, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0x3A, 0x7, 0xD, 0x24, 0xD, 0xD, 0xD, 0x7, 0x7, 0x7, 0x7, - 0x7, 0xD, 0x3B, 0x3B, 0x1F, 0x3B, 0x3B, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0x8, - 0x18, 0x10, 0x35, 0x1F, 0x1F, 0x8, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x3B, 0x3B, 0x3B, 0x1F, 0x1F, 0x1F, 0x1F, 0x3B, 0x20, 0x17, 0x3B, - 0x8, 0x3B, 0x8, 0x1F, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x8, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x3B, 0x3B, 0x8, - 0x8, 0x8, 0x3B, 0x3B, 0x8, 0x8, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x8, 0x3B, 0x3B, - 0x3B, 0x3B, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x35, 0x10, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x1F, 0x3B, 0x8, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x1F, - 0x1F, 0x35, 0x1F, 0x1F, 0x35, 0x3B, 0x3B, 0x3B, 0x3, 0x8, 0x8, 0x8, 0x8, 0x8, - 0x3B, 0x3B, 0x8, 0x8, 0x8, 0x8, 0x3B, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x8, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x8, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x8, 0x3B, 0x3B, 0x4, 0x2C, 0x8, 0x1B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x19, 0x20, 0x20, 0x8, 0x3C, 0x3B, 0x27, 0x8, - 0x3B, 0x8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD, 0x18, 0xD, - 0x18, 0xD, 0x18, 0xD, 0x18, 0xD, 0x18, 0xD, 0x18, 0xD, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0xD, 0x18, 0xD, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD, - 0x18, 0xD, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD, 0x18, 0x18, 0x18, - 0x18, 0x18, 0xD, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0xD, 0x18, 0x18, 0xD, 0xD, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0xD, 0x18, 0xD, 0x18, 0xD, 0xD, 0xD, 0x3B, 0x3B, 0x3, 0x3, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3, 0x3, 0x3, 0x3B, 0x3B, 0x3B, 0x3, 0x3, 0x3B, 0x8, 0x3B, - 0x3, 0x3, 0x8, 0x8, 0x8, 0x8, 0x3B, 0xD, 0xD, 0xD, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0xD, 0xD, 0xD, 0x3B, 0x3B, 0x3B, 0x1F, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3C, 0x20, 0x19, 0x17, 0x12, 0x12, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x13, 0x13, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x1F, 0x1F, 0x1F, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x8, - 0x8, 0x8, 0x1F, 0x35, 0x1F, 0x3B, 0x3B, 0x3B, 0x8, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x1F, 0x1F, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0x21, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x8, 0x8, 0x8, 0x8, - 0x8, 0x8, 0x8, 0x3B, 0x3B, 0x8, 0x8, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x8, 0x3B, - 0x3B, 0x3, 0x8, 0x1F, 0x3B, 0x8, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x8, 0x8, - 0x3B, 0x3B, 0x3B, 0x8, 0x3B, 0x8, 0x8, 0x8, 0x8, 0x3B, 0x8, 0x3B, 0x8, 0x1F, - 0x1F, 0x1F, 0x18, 0x18, 0x18, 0x1F, 0x2D, 0x3B, 0x3B, 0x3B, 0x10, 0x18, 0x18, - 0x1F, 0x1F, 0x35, 0x1F, 0x35, 0x1F, 0x35, 0x35, 0x1F, 0x35, 0x35, 0x10, 0x18, - 0x18, 0x1F, 0x10, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x1F, 0x35, 0x3B, 0x10, 0x10, 0x18, 0x18, 0x10, 0x18, 0x1F, 0x35, - 0x10, 0x18, 0x18, 0x1F, 0x35, 0x1F, 0x1F, 0x35, 0x1F, 0x1F, 0x35, 0x10, 0x18, - 0x1F, 0x1F, 0x35, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x35, 0x1F, 0x1F, 0x1F, 0x3, - 0x3, 0x3, 0x3, 0x3, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x1C, 0x1C, 0x3, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0x3D, 0x3D, 0x3, 0x3, 0x3, 0x2A, 0x3D, - 0x3D, 0x3D, 0x3D, 0x3D, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x8, 0x8, 0x3B, 0x3B, 0x3B, 0x3B, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3B, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, - 0x3B, 0x35, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, - 0xD, 0xD, 0xD, 0xD, -}; - -static const uint16_t _swift_stdlib_normData_ranks[402] = { - 0x0, 0x24, 0x24, 0x2A, 0x36, 0x42, 0x44, 0x47, 0x4B, 0x4B, 0x4B, 0x4B, 0x0, - 0x0, 0x0, 0x0, 0x35, 0x0, 0x31, 0x5C, 0x63, 0x9B, 0x0, 0xE, 0xE, 0xE, 0x2E, - 0x0, 0x3F, 0x51, 0x59, 0x61, 0x0, 0x9, 0xE, 0x30, 0x30, 0x0, 0x0, 0x33, 0x33, - 0x48, 0x0, 0x1, 0xC, 0x18, 0x33, 0x0, 0x0, 0x5, 0x1F, 0x22, 0x0, 0x8, 0x3D, - 0x41, 0x4E, 0x0, 0x5, 0xA, 0xE, 0x12, 0x0, 0x2, 0x2, 0xC, 0xD, 0x0, 0x6, 0x6, - 0xB, 0xB, 0x0, 0x9, 0xC, 0x11, 0x11, 0x0, 0x5, 0xC, 0xC, 0x13, 0x0, 0x2, 0xA, - 0x1F, 0x24, 0x0, 0x2, 0x5, 0x6, 0x6, 0x0, 0x0, 0x15, 0x2D, 0x30, 0x0, 0x3, - 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x2, 0x2, 0x2, 0x0, 0x1, - 0x1, 0x1, 0x4, 0x0, 0x0, 0x0, 0x2, 0xC, 0x0, 0x1E, 0x23, 0x2C, 0x35, 0x0, 0x2, - 0x5, 0x6, 0x6, 0x0, 0x18, 0x1B, 0x1B, 0x1B, 0x0, 0x40, 0x80, 0xC0, 0xFB, 0x0, - 0x3A, 0x72, 0xAC, 0xE7, 0x0, 0x1D, 0x1D, 0x1D, 0x2A, 0x0, 0x4, 0x4, 0x7, 0xA, - 0x0, 0x5, 0x14, 0x1E, 0x26, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x1, 0x1, 0x1, - 0x0, 0x0, 0x3, 0x3, 0x4, 0x0, 0x10, 0x20, 0x20, 0x20, 0x0, 0x0, 0x8, 0x1F, - 0x32, 0x0, 0x6, 0x6, 0x6, 0x6, 0x0, 0x0, 0x0, 0xB, 0xD, 0x0, 0x2, 0x2, 0x2, - 0x2, 0x0, 0x1, 0x2, 0x2, 0x3, 0x0, 0x5, 0x6, 0x6, 0x8, 0x0, 0x0, 0x0, 0x8, - 0xA, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x20, 0x60, 0xA0, 0x0, 0x40, 0x74, - 0xB2, 0xF2, 0x0, 0x1A, 0x30, 0x3D, 0x3D, 0x0, 0x10, 0x10, 0x10, 0x10, 0x0, - 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x5, 0x5, 0x5, 0x5, 0x0, - 0x0, 0x2, 0x6, 0x6, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x4, 0x4, 0x4, 0x0, - 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0xB, 0xF, 0xF, 0x0, 0x0, 0x3, 0x8, 0x8, 0x0, - 0x5, 0x6, 0x8, 0x8, 0x0, 0x2, 0x2, 0x2, 0x4, 0x0, 0xE, 0x13, 0x13, 0x13, 0x0, - 0x3, 0x9, 0xB, 0xB, 0x0, 0x0, 0x5, 0x5, 0x6, 0x0, 0x0, 0x2, 0x2, 0x3, 0x0, - 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x4, 0x5, 0x0, 0x0, 0x1, 0x3, 0x3, 0x0, - 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x3, 0x4, 0x0, 0x0, 0x0, 0x5, 0xC, 0x0, - 0x0, 0x2, 0x2, 0x2, 0x0, 0x0, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1F, 0x29, 0x29, 0x2C, 0x0, 0x0, 0x0, 0x0, 0x26, 0x0, 0x0, 0x0, 0x0, 0x7, - 0x0, 0x0, 0x1, 0x5, 0x5, 0x0, 0x7, 0x7, 0xE, 0xE, 0x0, 0x0, 0x30, 0x70, 0xB0, - 0x0, 0x40, 0x80, 0xC0, 0x100, 0x0, 0x40, 0x4E, 0x4E, 0x4E, -}; - -static const uint64_t _swift_stdlib_normData[403] = { - 0xC, 0x6D03FFE5FFFF, 0x0, 0x3F0000000, 0xEC1C9C0000000000, 0x1BFF, 0x4200000, - 0x60000400000000, 0x1058, 0x0, 0x0, 0x0, 0x3800, 0x0, 0x0, 0x0, - 0xBE7EFFBF3E7EFFBF, 0xFFFF, 0xF1F87EF1FF3FFFFC, 0x7FFFFF3FFFF3, - 0xE000000180030000, 0xFFFFFF31FFCFDFFF, 0x45CFFF, 0xFFFC0, 0x0, 0x0, - 0xFFFFFFFF00000000, 0xEEFFFF, 0xFFFFFFFF7FFFFFFF, 0xFC000001D7E04010, - 0x187C000001, 0x200708B0000, 0x12C0200, 0xC00000708B0000, 0xF8, - 0x33FFCFCFCCF0006, 0x0, 0x18E0000, 0x0, 0xB6BFFFFFFFFFFE, 0x0, - 0xF8000000007C07FF, 0x1BEFFFF, 0x10000, 0x9FC8000500000000, 0x2000000003D9F, - 0x7FFFFFF0000, 0x2160000, 0x0, 0xF800000000000000, 0x3EEFFBC00000200F, - 0xE0000000000, 0x2490000, 0xFF000000, 0xFFFFFFFBFFFFFC00, 0x1012020000000000, - 0xFF1E2000, 0x26B0000, 0x3800500000000000, 0x40000000B080, 0x2000104800000000, - 0x4E00, 0x2B90000, 0x200010000000, 0x0, 0x30C0390050000000, 0x10000000000000, - 0x2CB0000, 0x803C004000, 0x0, 0x6021001000, 0x0, 0x2D81000, 0x602D85, - 0x5800000000000000, 0x803C00, 0x0, 0x2E48400, 0xF400, 0xF00070000000000, 0x0, - 0xF00070000000000, 0x2F70000, 0x300000000000000, 0x1084200802A00000, - 0x200800DF3D7E0200, 0x4002001084, 0x30A0000, 0x4040000000000000, 0x680, - 0x20000000, 0x0, 0x32E0000, 0x0, 0x3FFFFE00000000, 0xFFFFFF0000000000, 0x7, - 0x3340000, 0xE000000000000000, 0x0, 0x0, 0x0, 0x3640000, 0x0, 0x0, 0x0, - 0x1000000030, 0x3670000, 0x0, 0x2004000000000000, 0x0, 0x0, 0x36A0000, - 0x200000000000000, 0x0, 0x0, 0xE00, 0x36C0000, 0x0, 0x0, 0x1800000, - 0x9FE0000100000000, 0x3700000, 0x7FFFBFFF00000000, 0x5540000000000000, - 0x1B283000000004, 0xFF8000000, 0x37C0000, 0xC00, 0xC0040, 0x800000, 0x0, - 0x3B10000, 0x21FDFFF700000000, 0x310, 0x0, 0x0, 0x3B70000, 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFF0BFFFFFF, 0x3D2FFFF, - 0xFFFF03FFFFFFFFFF, 0x3F3FFFFFFFFF3F3F, 0xFFFF3FFFFFFFAAFF, - 0xFFDE5FDFFFFFFFFF, 0x4DDEFCF, 0x33FDCFFFF, 0x0, 0x0, 0x1FFF000000000000, - 0x5D1FFE2, 0xC40000000000001, 0x0, 0x40000C0000000000, 0xE0000000, 0x6070000, - 0x5000001210, 0x333E00500000292, 0xF00000000333, 0x3C0F00000000, 0x6110000, - 0x6000000, 0x0, 0x0, 0x0, 0x6370000, 0x0, 0x10000000, 0x0, 0x0, 0x6390000, - 0x0, 0x38000, 0x0, 0x80000000, 0x63A0000, 0xFFFF000000000000, 0xFFFF, 0x0, - 0x0, 0x63E0000, 0x0, 0x50000000FC000000, 0x36DB02A55555, 0x2A5555550004610, - 0x65E36DB, 0x47900000, 0x0, 0x0, 0x0, 0x69A0000, 0x0, 0x0, 0x3FF0800000000000, - 0xC0000000, 0x6A00000, 0x300000000, 0x0, 0x0, 0x0, 0x6AD0000, 0x4000000000, - 0x1000, 0x0, 0x1000000000, 0x6AFFFFF, 0x3800000000000003, 0x800000000, 0x0, - 0x10008, 0x6C20000, 0x0, 0x0, 0xC19D000000000000, 0x40000000000002, 0x6CA0000, - 0x0, 0x0, 0x0, 0x20000000, 0x6D40000, 0x0, 0xFFFFFFFF00000000, - 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x6D5FFFF, 0xFFFFFFFFFFFFFFFF, - 0xFC657FE53FFFFFFF, 0x3FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x785FFFF, - 0x3FFFFFF, 0x5F7FFC00E0000000, 0x7FDB, 0x0, 0x8870000, 0xFFFF000000000000, - 0x0, 0x0, 0x0, 0x8C40000, 0x0, 0x0, 0x0, 0x20000000, 0x8D40000, 0x0, 0x0, - 0x1000000000000, 0x0, 0x8D50000, 0x7C0000000000000, 0x0, 0x0, 0x0, 0x8D60000, - 0x0, 0xA00000000000, 0x87000000, 0x0, 0x8DB0000, 0x60000000000000, 0x0, 0x0, - 0x0, 0x8E10000, 0x0, 0xF00000, 0x0, 0x0, 0x8E30000, 0x0, 0x0, 0x0, 0x1800, - 0x8E70000, 0x0, 0x1FFC00000, 0x3C0000, 0x0, 0x8E90000, 0x0, - 0x8001000000000040, 0x600080014000000, 0x0, 0x8F80007, 0x18C0800000, - 0x800000000, 0x401000000000000, 0x0, 0x9030000, 0x600000, 0x0, 0x0, 0x600, - 0x90B0000, 0x1FC0008038005800, 0x1F, 0x0, 0x0, 0x90F0000, 0x40000044, - 0x7C01000000000000, 0xC, 0x0, 0x9220000, 0x0, 0x18C0080000000, 0x0, - 0x800000000000, 0x92D0000, 0x0, 0xC00000, 0x0, 0x800, 0x9330000, 0x0, 0x0, - 0x0, 0x600, 0x9360000, 0x0, 0x0, 0x6101000000000000, 0x8, 0x9380000, 0x0, - 0x10000, 0x80001000000000, 0x0, 0x93D0200, 0x0, 0x0, 0x8000, 0x0, 0x9410000, - 0x0, 0x0, 0x34, 0x800000, 0x9420000, 0x0, 0x0, 0x1F00000000, 0x7F00000000, - 0x9460000, 0x0, 0x30000, 0x0, 0x0, 0x9520000, 0x0, 0x4000000000000000, 0x0, - 0x0, 0x9540000, 0x0, 0x0, 0x0, 0x0, 0x955C000, 0xFE7F807E3FF, 0x1F8003C00, - 0x0, 0x1C00000000, 0x9570000, 0x0, 0x0, 0x0, 0x7DBF9FFFF7F0000, 0x9830000, - 0x0, 0x0, 0x0, 0x7F000000000000, 0x9A90000, 0x0, 0x4000, 0xF000, 0x0, - 0x9B00000, 0x7F0000, 0x0, 0x7F0, 0x0, 0x9B50000, 0x0, 0xFFFFFFFFFFFF0000, - 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x9C3FFFF, 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xA83FFFF, - 0xFFFFFFFFFFFFFFFF, 0x3FFF, 0x0, 0x0, 0xB930000, -}; - -#define NFD_DECOMP_LEVEL_COUNT 11 - -static const uint16_t _swift_stdlib_nfd_decomp_sizes[11] = { - 0x80D, 0x4F8, 0x32E, 0x1EF, 0x137, 0xC3, 0x7B, 0x54, 0x40, 0x40, 0x40, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys0[33] = { - 0xA610E3C4A94D1E98, 0x4360A421841EF395, 0x4A0E48481C9E3B08, - 0x8B20EA3110533240, 0xC061C012EA208593, 0x95C804089E38538B, - 0x17084374F3DF67A1, 0x5158D1B16C820914, 0x3D2C95027217D407, - 0xE0A8002869046382, 0xD2B2DA86D21400D, 0xE84418198616B103, 0x2C022C18A11A4589, - 0x18D0391017E61E1, 0x54192C84C6AE0E01, 0x6418A05096560544, 0x4C099C24942F500D, - 0xCA734C8250149DED, 0x8C6150D379A881C8, 0x1252A6506620EB68, - 0xC00B1A258990DC9C, 0x48058A3583C1D8F4, 0x130FD1922DE0BA0, 0xD1098D6244CFC060, - 0xB8D48414124B032E, 0xA164FF04EBE4961B, 0x21DBF90ED081085, 0x9290B24898B8A16, - 0xD08E25DE422898A5, 0x9054380D01CFC262, 0x12209144B002A104, - 0xE201C04A10504414, 0x519, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys1[20] = { - 0x8144CC4A0D2250A4, 0x8D7027B878E6AF00, 0xC8808058019A1327, - 0x8440182CDA8A8000, 0x11F2546640A88578, 0x809941041616F30A, - 0x81EA43018F6211B3, 0xDF5248898CC52106, 0x706040F034804ACA, - 0xC466784A249C4D00, 0xD6A01234AE244BA2, 0x4E7E81014034B644, 0x4C4A90003B01AA1, - 0x505241F44B1C495A, 0xB1C12D3C10609621, 0x219508C06A2B8021, - 0xD888C002DC100EA5, 0xA5031DD40B961481, 0x3618E0842D48E703, 0x24462188051181, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys2[13] = { - 0x18688558A53CB60D, 0x4CF22409093204F, 0x33717C5A9D12141A, 0x276322F3444A8164, - 0x81540E02747F08D0, 0x8116C1618AA2A163, 0x109AAB2395D06B8, 0x8E7142BC806600BB, - 0x387205C91105908, 0x1460C4392FAE5909, 0x52DA004F130A8506, 0x6A886C8311090735, - 0x24B8FCD40E21, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys3[8] = { - 0x60A631406899DC30, 0xB2A84020DD5240B1, 0x149D1EE14D820B49, 0xC8CAFB380940121, - 0x300040A927914309, 0x6B027CBCC7050271, 0x2623507C35B2408B, 0x832091C1B4, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys4[5] = { - 0x78605890CC980E05, 0x2C28AA1106247AAB, 0xB83855821C09229F, - 0x1610C434CFB82648, 0xB2A8351190804, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys5[4] = { - 0x42B00C82848316E9, 0x481902D129498466, 0xF0126DE0FA042361, 0x1, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys6[2] = { - 0x800862A20C0592A5, 0xCA94800F00F862, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys7[2] = { - 0xA703754B0198000, 0x73104, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys8[1] = { - 0x2436652504A5F5CA, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys9[1] = { - 0x6198C101C6044C21, -}; - -static const uint64_t _swift_stdlib_nfd_decomp_keys10[1] = { - 0x404228114000004, -}; - -static const uint64_t * const _swift_stdlib_nfd_decomp_keys[11] = { - _swift_stdlib_nfd_decomp_keys0, _swift_stdlib_nfd_decomp_keys1, - _swift_stdlib_nfd_decomp_keys2, _swift_stdlib_nfd_decomp_keys3, - _swift_stdlib_nfd_decomp_keys4, _swift_stdlib_nfd_decomp_keys5, - _swift_stdlib_nfd_decomp_keys6, _swift_stdlib_nfd_decomp_keys7, - _swift_stdlib_nfd_decomp_keys8, _swift_stdlib_nfd_decomp_keys9, - _swift_stdlib_nfd_decomp_keys10, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks0[5] = { - 0x0, 0xCC, 0x185, 0x253, 0x310, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks1[3] = { - 0x315, 0x3D0, 0x488, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks2[2] = { - 0x4DF, 0x5AB, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks3[1] = { - 0x61E, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks4[1] = { - 0x6D6, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks5[1] = { - 0x74A, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks6[1] = { - 0x792, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks7[1] = { - 0x7B9, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks8[1] = { - 0x7D4, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks9[1] = { - 0x7F0, -}; - -static const uint16_t _swift_stdlib_nfd_decomp_ranks10[1] = { - 0x804, -}; - -static const uint16_t * const _swift_stdlib_nfd_decomp_ranks[11] = { - _swift_stdlib_nfd_decomp_ranks0, _swift_stdlib_nfd_decomp_ranks1, - _swift_stdlib_nfd_decomp_ranks2, _swift_stdlib_nfd_decomp_ranks3, - _swift_stdlib_nfd_decomp_ranks4, _swift_stdlib_nfd_decomp_ranks5, - _swift_stdlib_nfd_decomp_ranks6, _swift_stdlib_nfd_decomp_ranks7, - _swift_stdlib_nfd_decomp_ranks8, _swift_stdlib_nfd_decomp_ranks9, - _swift_stdlib_nfd_decomp_ranks10, -}; - -static const uint8_t _swift_stdlib_nfd_decomp[9435] = { - 0x4, 0xF0, 0xA4, 0xBE, 0xA1, 0x3, 0x69, 0xCC, 0x82, 0x3, 0x5A, 0xCC, 0xB1, - 0x3, 0xE5, 0xBD, 0x93, 0x3, 0xE7, 0x80, 0x9E, 0x3, 0xE5, 0xB5, 0xAB, 0x6, - 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0xE5, 0xAC, 0xBE, 0x3, 0xE8, 0xB7, - 0x8B, 0x5, 0x41, 0xCC, 0x82, 0xCC, 0x80, 0x6, 0xE3, 0x81, 0xB8, 0xE3, 0x82, - 0x9A, 0x3, 0xE7, 0x8E, 0x87, 0x3, 0xE7, 0x91, 0xB1, 0x3, 0x55, 0xCC, 0x88, - 0x3, 0xE8, 0x91, 0x89, 0x3, 0xE9, 0xA7, 0xB1, 0x3, 0xE4, 0x95, 0x9D, 0x5, - 0x61, 0xCC, 0x82, 0xCC, 0x81, 0x3, 0x63, 0xCC, 0x87, 0x6, 0xE0, 0xA4, 0xA2, - 0xE0, 0xA4, 0xBC, 0x4, 0xD7, 0xA1, 0xD6, 0xBC, 0x3, 0xE5, 0xBE, 0xAD, 0x8, - 0xF0, 0x91, 0x8D, 0x87, 0xF0, 0x91, 0x8C, 0xBE, 0x3, 0xE8, 0x8A, 0x9D, 0x3, - 0xE5, 0x8B, 0xBA, 0x6, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85, 0x5, 0xE2, 0xAB, - 0x9D, 0xCC, 0xB8, 0x3, 0xE4, 0xA9, 0xB6, 0x3, 0x75, 0xCC, 0x9B, 0x3, 0x43, - 0xCC, 0x82, 0x3, 0x43, 0xCC, 0xA7, 0x3, 0xE6, 0x8E, 0x83, 0x3, 0xE6, 0x86, - 0xB2, 0x4, 0xCE, 0xBF, 0xCC, 0x81, 0x3, 0xE9, 0x99, 0x8B, 0x3, 0x6F, 0xCC, - 0x80, 0x4, 0xF0, 0xAA, 0x8A, 0x91, 0x3, 0xE4, 0xBB, 0xA4, 0x3, 0xE3, 0xAE, - 0x9D, 0x3, 0xE6, 0x96, 0x99, 0x3, 0xE8, 0x90, 0xBD, 0x5, 0x45, 0xCC, 0x82, - 0xCC, 0x89, 0x3, 0xE9, 0x9D, 0x96, 0x3, 0xE8, 0xA6, 0x96, 0x4, 0xCE, 0x99, - 0xCC, 0x94, 0x3, 0x6F, 0xCC, 0xA3, 0x3, 0xE8, 0x9A, 0x88, 0x3, 0xE5, 0x93, - 0xB6, 0x6, 0xE0, 0xA4, 0x97, 0xE0, 0xA4, 0xBC, 0x3, 0xE3, 0xBC, 0x9B, 0x3, - 0x4F, 0xCC, 0x88, 0x4, 0xCE, 0x9F, 0xCC, 0x81, 0x4, 0xD7, 0xB2, 0xD6, 0xB7, - 0x3, 0xE4, 0xA7, 0xA6, 0x8, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, - 0x8, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE5, 0x8D, 0xB3, - 0x3, 0xE6, 0x90, 0x9C, 0x4, 0xF0, 0xA3, 0xBB, 0x91, 0x3, 0xE8, 0x8C, 0xA3, - 0x3, 0xE5, 0xA3, 0x9F, 0x4, 0xF0, 0xA4, 0x8B, 0xAE, 0x3, 0xE6, 0x9C, 0x80, - 0x3, 0x69, 0xCC, 0xA8, 0x3, 0x67, 0xCC, 0x82, 0x3, 0x47, 0xCC, 0x84, 0x3, - 0x4F, 0xCC, 0x8C, 0x5, 0x55, 0xCC, 0x9B, 0xCC, 0x80, 0x3, 0xE9, 0xA6, 0xA7, - 0x3, 0x75, 0xCC, 0x8C, 0x3, 0xE4, 0x80, 0x98, 0x6, 0xE1, 0xAC, 0x91, 0xE1, - 0xAC, 0xB5, 0x3, 0xE7, 0xB8, 0x89, 0x6, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x80, - 0x6, 0xE0, 0xA4, 0x95, 0xE0, 0xA4, 0xBC, 0x3, 0xE7, 0xA7, 0x8A, 0x3, 0xE4, - 0x84, 0xAF, 0x3, 0xE5, 0xB3, 0x80, 0x3, 0xE7, 0x81, 0xBD, 0x3, 0x4F, 0xCC, - 0x80, 0x3, 0xE7, 0xA5, 0x9D, 0x3, 0xE8, 0xA3, 0xA1, 0x4, 0xD0, 0x95, 0xCC, - 0x88, 0x3, 0xE8, 0xAB, 0x8B, 0x4, 0xCE, 0xA5, 0xCC, 0x88, 0x3, 0xE9, 0x85, - 0xAA, 0x4, 0xF0, 0xA8, 0xB5, 0xB7, 0x3, 0xE5, 0x8D, 0xBD, 0x5, 0x4F, 0xCC, - 0x84, 0xCC, 0x81, 0x3, 0x61, 0xCC, 0x8A, 0x6, 0xE0, 0xA4, 0xAF, 0xE0, 0xA4, - 0xBC, 0x6, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x82, 0x3, 0xE5, 0xA7, 0x98, 0x6, - 0xE0, 0xA6, 0xA1, 0xE0, 0xA6, 0xBC, 0x5, 0x4F, 0xCC, 0x83, 0xCC, 0x81, 0x3, - 0x6F, 0xCC, 0x8F, 0x6, 0xE0, 0xA7, 0x87, 0xE0, 0xA6, 0xBE, 0x3, 0xE7, 0x8E, - 0xB2, 0x3, 0xE4, 0x81, 0x86, 0x3, 0xE8, 0xA6, 0x86, 0x3, 0xE5, 0x87, 0x9E, - 0x3, 0xE9, 0xBC, 0x8F, 0x3, 0x4F, 0xCC, 0x91, 0x3, 0xE9, 0xA4, 0xA8, 0x3, - 0xE6, 0x83, 0x87, 0x3, 0x4B, 0xCC, 0x81, 0x3, 0x65, 0xCC, 0x88, 0x3, 0xE5, - 0x8B, 0xA4, 0x3, 0x49, 0xCC, 0x8C, 0x3, 0xE4, 0x95, 0xA1, 0x3, 0xE6, 0xB1, - 0x8E, 0x4, 0xC3, 0xA6, 0xCC, 0x84, 0x9, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8F, - 0xE0, 0xB7, 0x8A, 0x3, 0x6E, 0xCC, 0x83, 0x6, 0xCE, 0x91, 0xCC, 0x93, 0xCD, - 0x82, 0x3, 0x55, 0xCC, 0x80, 0x3, 0xE5, 0x96, 0xAB, 0x3, 0xE4, 0x95, 0xAB, - 0x3, 0xE5, 0xB9, 0xB4, 0x3, 0xE6, 0xB2, 0xBF, 0x3, 0x59, 0xCC, 0x87, 0x5, - 0x4F, 0xCC, 0x9B, 0xCC, 0x89, 0x3, 0xE7, 0x9C, 0x9E, 0x3, 0xE4, 0xBA, 0x82, - 0x4, 0xC2, 0xA8, 0xCD, 0x82, 0x6, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85, 0x3, - 0xE8, 0x99, 0xA9, 0x3, 0xE5, 0xBC, 0xA2, 0x3, 0xE8, 0xAA, 0xA0, 0x6, 0xE3, - 0x81, 0xBB, 0xE3, 0x82, 0x9A, 0x3, 0x77, 0xCC, 0x81, 0x6, 0xCE, 0x9F, 0xCC, - 0x94, 0xCC, 0x81, 0x4, 0xCF, 0x85, 0xCC, 0x81, 0x3, 0xE7, 0x9B, 0xB4, 0x3, - 0xE5, 0xAC, 0xA8, 0x3, 0xE5, 0x8B, 0xB5, 0x3, 0x42, 0xCC, 0xA3, 0x3, 0xE8, - 0xB6, 0xBC, 0x3, 0x4B, 0xCC, 0xA3, 0x3, 0xE4, 0xBE, 0x86, 0x3, 0xE4, 0xAC, - 0xB3, 0x6, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x82, 0x6, 0xE3, 0x81, 0xB2, 0xE3, - 0x82, 0x99, 0x3, 0xE7, 0xB4, 0xA2, 0x3, 0x75, 0xCC, 0xAD, 0x4, 0xD0, 0xA3, - 0xCC, 0x84, 0x3, 0xE9, 0xBA, 0xBB, 0x3, 0xE8, 0xAB, 0xB8, 0x4, 0xC3, 0x86, - 0xCC, 0x81, 0x3, 0x61, 0xCC, 0x86, 0x3, 0xE3, 0x92, 0x9E, 0x3, 0xE6, 0x91, - 0xBE, 0x5, 0x4F, 0xCC, 0x87, 0xCC, 0x84, 0x3, 0x53, 0xCC, 0x81, 0x3, 0xE6, - 0x8B, 0x89, 0x3, 0x6E, 0xCC, 0x81, 0x8, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81, - 0xCD, 0x85, 0x6, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x81, 0x6, 0xCE, 0xB1, 0xCC, - 0x94, 0xCD, 0x85, 0x3, 0x41, 0xCC, 0xA8, 0x3, 0xE9, 0x8B, 0x98, 0x5, 0x61, - 0xCC, 0x86, 0xCC, 0x81, 0x6, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81, 0x4, 0xCE, - 0xB5, 0xCC, 0x94, 0x3, 0xE8, 0x93, 0xAE, 0x3, 0xE9, 0xBB, 0xB9, 0x3, 0x6C, - 0xCC, 0xB1, 0x5, 0x41, 0xCC, 0xA3, 0xCC, 0x82, 0x3, 0xE7, 0x91, 0x87, 0x3, - 0xE7, 0xB7, 0xB4, 0x3, 0xE6, 0x8D, 0xA8, 0x3, 0x49, 0xCC, 0x82, 0x3, 0x6A, - 0xCC, 0x8C, 0x3, 0xE5, 0x8B, 0x87, 0x5, 0x65, 0xCC, 0x84, 0xCC, 0x80, 0x6, - 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x9F, 0x4, 0xF0, 0xA1, 0x93, 0xA4, 0x3, 0xE7, - 0x9D, 0x80, 0x3, 0x41, 0xCC, 0x87, 0x3, 0xE7, 0x90, 0x89, 0x3, 0xE5, 0xB1, - 0xA2, 0x4, 0xDB, 0x81, 0xD9, 0x94, 0x6, 0xCE, 0xB1, 0xCC, 0x80, 0xCD, 0x85, - 0x6, 0xE0, 0xAF, 0x86, 0xE0, 0xAF, 0x97, 0x4, 0xF0, 0xA0, 0x94, 0x9C, 0x4, - 0xCE, 0xB9, 0xCC, 0x81, 0x3, 0xE5, 0x95, 0x95, 0x6, 0xCE, 0x97, 0xCC, 0x93, - 0xCC, 0x80, 0x3, 0xE9, 0xB9, 0xBF, 0x4, 0xD8, 0xA7, 0xD9, 0x95, 0x3, 0x46, - 0xCC, 0x87, 0x3, 0xE7, 0x82, 0xAD, 0x3, 0xE7, 0xB2, 0x92, 0x3, 0xE7, 0x9B, - 0x9B, 0x4, 0xF0, 0xA9, 0x92, 0x96, 0x3, 0xE6, 0x97, 0xA3, 0x3, 0xE4, 0xAA, - 0xB2, 0x3, 0x73, 0xCC, 0x8C, 0x3, 0x61, 0xCC, 0x87, 0x4, 0xD7, 0x98, 0xD6, - 0xBC, 0x3, 0xE9, 0x9B, 0x83, 0x5, 0x73, 0xCC, 0x81, 0xCC, 0x87, 0x3, 0xE9, - 0x96, 0x8B, 0x3, 0xE7, 0xBD, 0xB9, 0x3, 0xE5, 0x8D, 0x91, 0x3, 0xE8, 0x98, - 0xAD, 0x3, 0xE7, 0xA2, 0x8C, 0x3, 0x7A, 0xCC, 0xB1, 0x3, 0x45, 0xCC, 0x91, - 0x6, 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99, 0x3, 0xE4, 0xB8, 0xB8, 0x3, 0xE4, - 0xBA, 0xAE, 0x6, 0xE0, 0xA7, 0x87, 0xE0, 0xA7, 0x97, 0x3, 0xE4, 0xBD, 0xA0, - 0x8, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0x3, 0x7A, 0xCC, 0x82, - 0x3, 0xE5, 0xB1, 0xAE, 0x5, 0xE2, 0x89, 0xB6, 0xCC, 0xB8, 0x3, 0xE5, 0xA0, - 0xB2, 0x5, 0xE1, 0xBF, 0xBE, 0xCC, 0x81, 0x3, 0xE6, 0x83, 0xA1, 0x4, 0xF0, - 0xA9, 0x88, 0x9A, 0x3, 0xE8, 0x97, 0x8D, 0x3, 0x49, 0xCC, 0x87, 0x4, 0xCE, - 0x9F, 0xCC, 0x80, 0x3, 0xE9, 0xBB, 0x8E, 0x3, 0xE9, 0x99, 0xB8, 0x3, 0xE7, - 0x95, 0x99, 0x3, 0xE5, 0xBB, 0x99, 0x3, 0xE9, 0xB7, 0xBA, 0x4, 0xCE, 0x91, - 0xCC, 0x81, 0x6, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0x4, 0xF0, 0xA2, 0x8C, - 0xB1, 0x3, 0xE8, 0xA5, 0x81, 0x3, 0x73, 0xCC, 0x81, 0x3, 0xE6, 0x8E, 0xA0, - 0x3, 0xE3, 0xA4, 0xBA, 0x3, 0xE6, 0x9C, 0x9B, 0x3, 0x5A, 0xCC, 0x82, 0x3, - 0xE8, 0x87, 0xAD, 0x3, 0xE9, 0x9D, 0x88, 0x3, 0xE5, 0x85, 0xA4, 0x3, 0xE7, - 0xB6, 0xA0, 0x3, 0x59, 0xCC, 0x80, 0x3, 0xE5, 0xB5, 0xBC, 0x3, 0xE8, 0xBE, - 0xB6, 0x4, 0xF0, 0xA3, 0x8F, 0x83, 0x3, 0xE2, 0x80, 0x83, 0x3, 0x61, 0xCC, - 0xA8, 0x3, 0xE8, 0xA3, 0xBA, 0x4, 0xCE, 0xB7, 0xCC, 0x81, 0x3, 0xE7, 0xA6, - 0x8E, 0x3, 0xE5, 0x88, 0x87, 0x3, 0xE9, 0xBE, 0x8E, 0x3, 0xE7, 0x86, 0x9C, - 0x3, 0xE5, 0xA4, 0x9A, 0x3, 0xE6, 0xAB, 0x93, 0x3, 0xE6, 0xA2, 0x85, 0x6, - 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82, 0x3, 0xE7, 0x95, 0xA5, 0x6, 0xCE, 0xA9, - 0xCC, 0x93, 0xCC, 0x81, 0x3, 0xE4, 0x8C, 0xB4, 0x3, 0xE3, 0xAC, 0x99, 0x3, - 0xE6, 0xB4, 0x96, 0x3, 0xE6, 0x85, 0xA8, 0x3, 0xE6, 0x8B, 0x8F, 0x3, 0xE5, - 0xB4, 0x99, 0x3, 0xE9, 0xAD, 0xAF, 0x6, 0xE1, 0xAC, 0x8D, 0xE1, 0xAC, 0xB5, - 0x5, 0xE2, 0x89, 0xB3, 0xCC, 0xB8, 0x4, 0xCE, 0xB9, 0xCC, 0x84, 0x3, 0xE8, - 0xB1, 0x88, 0x3, 0xE6, 0x97, 0x85, 0x4, 0xCE, 0xA9, 0xCC, 0x93, 0x4, 0xD0, - 0xB0, 0xCC, 0x86, 0x3, 0xE8, 0x88, 0x98, 0x3, 0xE6, 0xBB, 0x9B, 0x5, 0x55, - 0xCC, 0x9B, 0xCC, 0x83, 0x3, 0x59, 0xCC, 0x81, 0x4, 0xF0, 0xA6, 0x8B, 0x99, - 0x3, 0xE8, 0x80, 0x85, 0x3, 0xE4, 0xA9, 0xAE, 0x3, 0xE8, 0xBC, 0xA6, 0x6, - 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x85, 0x3, 0x69, 0xCC, 0x84, 0x3, 0xE6, 0x9D, - 0x9E, 0x6, 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82, 0x5, 0x45, 0xCC, 0xA3, 0xCC, - 0x82, 0x4, 0xCF, 0x89, 0xCC, 0x94, 0x6, 0xE0, 0xAF, 0x87, 0xE0, 0xAE, 0xBE, - 0x4, 0xF0, 0xA3, 0x8E, 0x9C, 0x3, 0x45, 0xCC, 0x8C, 0x3, 0xE7, 0xA4, 0xBE, - 0x6, 0xE0, 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0x5, 0x52, 0xCC, 0xA3, 0xCC, 0x84, - 0x3, 0xE7, 0x9C, 0x9F, 0x6, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, 0x3, 0xE7, - 0x8C, 0xAA, 0x3, 0xE7, 0xB1, 0xBB, 0x6, 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x99, - 0x5, 0x53, 0xCC, 0xA3, 0xCC, 0x87, 0x3, 0xE8, 0xAA, 0xAA, 0x2, 0xCE, 0xA9, - 0x3, 0xE5, 0x8C, 0x86, 0x4, 0xCF, 0x89, 0xCC, 0x81, 0x3, 0x4F, 0xCC, 0x83, - 0x5, 0xE2, 0x8A, 0xA9, 0xCC, 0xB8, 0x3, 0xE6, 0xB7, 0x8B, 0x3, 0x45, 0xCC, - 0xAD, 0x3, 0xE8, 0xBE, 0xB0, 0x4, 0xF0, 0xAA, 0x83, 0x8E, 0x3, 0x4E, 0xCC, - 0xAD, 0x4, 0xD0, 0x98, 0xCC, 0x80, 0x3, 0xE5, 0x88, 0xA9, 0x3, 0x41, 0xCC, - 0x8F, 0x5, 0x4F, 0xCC, 0x9B, 0xCC, 0x81, 0x3, 0x4C, 0xCC, 0x81, 0x5, 0x4F, - 0xCC, 0x9B, 0xCC, 0x80, 0x6, 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x3, 0x61, - 0xCC, 0x83, 0x3, 0xE6, 0x82, 0x94, 0x6, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, - 0x4, 0xCE, 0xB7, 0xCD, 0x82, 0x3, 0xE4, 0xB5, 0x96, 0x3, 0xE9, 0x87, 0x91, - 0x3, 0xE6, 0xAE, 0x9F, 0x3, 0x79, 0xCC, 0xA3, 0x8, 0xCE, 0xB1, 0xCC, 0x93, - 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE7, 0xA6, 0xAE, 0x6, 0xE3, 0x83, 0x98, 0xE3, - 0x82, 0x99, 0x5, 0x4F, 0xCC, 0x82, 0xCC, 0x89, 0x3, 0x45, 0xCC, 0x83, 0x3, - 0x49, 0xCC, 0x81, 0x6, 0xE0, 0xBD, 0x80, 0xE0, 0xBE, 0xB5, 0x3, 0xE5, 0x97, - 0xA2, 0x3, 0xE7, 0x88, 0xAB, 0x3, 0xE7, 0x95, 0xB0, 0x3, 0xE7, 0x94, 0xA4, - 0x3, 0xE7, 0xB0, 0xBE, 0x3, 0xE9, 0x9B, 0xA2, 0x3, 0x41, 0xCC, 0x81, 0x6, - 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x85, 0x4, 0xD0, 0x9E, 0xCC, 0x88, 0x4, 0xF0, - 0xA8, 0x9C, 0xAE, 0x4, 0xD1, 0xB5, 0xCC, 0x8F, 0x3, 0xE8, 0x9D, 0xB9, 0x3, - 0xE5, 0x86, 0x95, 0x6, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0x3, 0x45, 0xCC, - 0x82, 0x3, 0xE3, 0xA1, 0xA2, 0x3, 0xE6, 0x86, 0x8E, 0x3, 0x41, 0xCC, 0x91, - 0x3, 0xE5, 0xB5, 0xAE, 0x4, 0xD3, 0xA8, 0xCC, 0x88, 0x3, 0xE9, 0x80, 0xB8, - 0x3, 0x69, 0xCC, 0x8C, 0x3, 0xE6, 0x95, 0x8F, 0x4, 0xF0, 0xA6, 0x87, 0x9A, - 0x4, 0xF0, 0xA4, 0x9C, 0xB5, 0x3, 0xE9, 0x96, 0xB7, 0x3, 0xE8, 0xBB, 0x94, - 0x4, 0xCE, 0x91, 0xCC, 0x84, 0x3, 0x79, 0xCC, 0x89, 0x6, 0xE3, 0x81, 0x86, - 0xE3, 0x82, 0x99, 0x3, 0x58, 0xCC, 0x88, 0x3, 0x65, 0xCC, 0xAD, 0x5, 0x4F, - 0xCC, 0x84, 0xCC, 0x80, 0x4, 0xC5, 0xBF, 0xCC, 0x87, 0x6, 0xCE, 0x97, 0xCC, - 0x93, 0xCD, 0x85, 0x3, 0xE6, 0xA4, 0x94, 0x3, 0x6C, 0xCC, 0x8C, 0x5, 0x75, - 0xCC, 0x88, 0xCC, 0x80, 0x5, 0x4F, 0xCC, 0x9B, 0xCC, 0x83, 0x3, 0xE6, 0xAE, - 0xBA, 0x4, 0xF0, 0xA5, 0xAA, 0xA7, 0x3, 0xE8, 0x8A, 0xBD, 0x3, 0x57, 0xCC, - 0xA3, 0x8, 0xF0, 0x91, 0x82, 0xA5, 0xF0, 0x91, 0x82, 0xBA, 0x3, 0xE6, 0xB1, - 0xA7, 0x6, 0xE0, 0xA8, 0xB8, 0xE0, 0xA8, 0xBC, 0x3, 0x7A, 0xCC, 0xA3, 0x3, - 0xE5, 0xBF, 0x97, 0x4, 0xF0, 0xA1, 0xB7, 0xA6, 0x4, 0xC3, 0xB8, 0xCC, 0x81, - 0x3, 0x72, 0xCC, 0x8F, 0x5, 0x65, 0xCC, 0x84, 0xCC, 0x81, 0x3, 0x43, 0xCC, - 0x81, 0x3, 0xE8, 0x94, 0x96, 0x5, 0x55, 0xCC, 0x9B, 0xCC, 0x81, 0x3, 0xE9, - 0x88, 0xB8, 0x4, 0xCE, 0xA5, 0xCC, 0x84, 0x3, 0xE4, 0x98, 0xB5, 0x3, 0xE6, - 0xAD, 0xB7, 0x3, 0xE5, 0x86, 0x8D, 0x4, 0xD0, 0xB0, 0xCC, 0x88, 0x4, 0xC2, - 0xA8, 0xCC, 0x81, 0x3, 0x64, 0xCC, 0xAD, 0x3, 0x69, 0xCC, 0x89, 0x3, 0xE4, - 0xBE, 0x80, 0x4, 0xD7, 0xA8, 0xD6, 0xBC, 0x6, 0xCE, 0xB7, 0xCC, 0x80, 0xCD, - 0x85, 0x4, 0xF0, 0xA7, 0xA2, 0xAE, 0x4, 0xD0, 0xB8, 0xCC, 0x86, 0x3, 0xE8, - 0xB7, 0xAF, 0x3, 0x74, 0xCC, 0xA7, 0x3, 0x65, 0xCC, 0xA3, 0x4, 0xF0, 0xA6, - 0x8C, 0xBE, 0x5, 0x45, 0xCC, 0xA7, 0xCC, 0x86, 0x4, 0xD9, 0x88, 0xD9, 0x94, - 0x3, 0xE7, 0xBD, 0xBA, 0x3, 0xE5, 0xB0, 0x86, 0x5, 0xE2, 0x89, 0xA1, 0xCC, - 0xB8, 0x3, 0xE5, 0xB7, 0xA2, 0x4, 0xD7, 0x90, 0xD6, 0xB8, 0x3, 0xE8, 0x8B, - 0xA5, 0x4, 0xCE, 0xB1, 0xCD, 0x85, 0x3, 0x68, 0xCC, 0x8C, 0x3, 0xE5, 0x96, - 0x9D, 0x3, 0xE5, 0xB6, 0xB2, 0x3, 0xE7, 0xB5, 0xA3, 0x3, 0xE9, 0x86, 0x99, - 0x3, 0xE9, 0x83, 0xBD, 0x6, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0x3, 0xE9, - 0x84, 0x91, 0x4, 0xF0, 0xA2, 0xAF, 0xB1, 0x3, 0xE6, 0x88, 0xAE, 0x3, 0x69, - 0xCC, 0x88, 0x3, 0x4C, 0xCC, 0x8C, 0x3, 0x65, 0xCC, 0x89, 0x6, 0xCE, 0x99, - 0xCC, 0x94, 0xCD, 0x82, 0x3, 0xE5, 0x89, 0xB2, 0x6, 0xCF, 0x89, 0xCC, 0x93, - 0xCC, 0x80, 0x3, 0x73, 0xCC, 0xA7, 0x3, 0xE9, 0x89, 0xBC, 0x4, 0xF0, 0xA3, - 0xB4, 0x9E, 0x6, 0xE0, 0xA4, 0x9C, 0xE0, 0xA4, 0xBC, 0x3, 0xE7, 0xBE, 0x9A, - 0x5, 0x61, 0xCC, 0x88, 0xCC, 0x84, 0x3, 0xE6, 0xB3, 0xA5, 0x3, 0x45, 0xCC, - 0x86, 0x6, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x5, 0x41, 0xCC, 0x86, 0xCC, - 0x89, 0x3, 0xE6, 0x87, 0xB6, 0x3, 0xE6, 0x95, 0xAC, 0x3, 0xE5, 0x87, 0x9C, - 0x6, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0x99, 0x3, 0x75, 0xCC, 0xB0, 0x3, 0xE5, - 0x86, 0x92, 0x5, 0x6F, 0xCC, 0xA8, 0xCC, 0x84, 0x5, 0x55, 0xCC, 0x88, 0xCC, - 0x8C, 0x4, 0xCE, 0x91, 0xCC, 0x93, 0x8, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, - 0xCD, 0x85, 0x3, 0xE8, 0xA3, 0x82, 0x3, 0x72, 0xCC, 0x81, 0x3, 0xE9, 0xA7, - 0xBE, 0x4, 0xDB, 0x95, 0xD9, 0x94, 0x3, 0x44, 0xCC, 0x87, 0x3, 0x55, 0xCC, - 0xB0, 0x6, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x80, 0x3, 0x74, 0xCC, 0x88, 0x3, - 0x53, 0xCC, 0x8C, 0x3, 0xE8, 0x93, 0xB1, 0x8, 0xCE, 0xB1, 0xCC, 0x93, 0xCC, - 0x81, 0xCD, 0x85, 0x3, 0x4A, 0xCC, 0x82, 0x3, 0xE6, 0x92, 0x9A, 0x6, 0xCF, - 0x85, 0xCC, 0x88, 0xCC, 0x80, 0x3, 0xE5, 0xAF, 0xAE, 0x6, 0xE0, 0xBD, 0x96, - 0xE0, 0xBE, 0xB7, 0x4, 0xD7, 0x99, 0xD6, 0xBC, 0x2, 0xCE, 0xB9, 0x6, 0xE1, - 0xAD, 0x82, 0xE1, 0xAC, 0xB5, 0x3, 0xE8, 0x89, 0xB9, 0x3, 0x55, 0xCC, 0x89, - 0x3, 0xE8, 0x8D, 0x92, 0x3, 0x52, 0xCC, 0x87, 0x3, 0xE5, 0xB5, 0x90, 0x3, - 0xE8, 0x82, 0x8B, 0x3, 0x54, 0xCC, 0xA7, 0x3, 0xE9, 0x82, 0x94, 0x4, 0xF0, - 0xA6, 0xB3, 0x95, 0x2, 0xC2, 0xB4, 0x4, 0xF0, 0xA2, 0x86, 0x9F, 0x3, 0xE6, - 0x8B, 0x93, 0x4, 0xD0, 0xB3, 0xCC, 0x81, 0x3, 0xE5, 0xA5, 0xB3, 0x3, 0xE7, - 0x87, 0x90, 0x3, 0xE5, 0xBD, 0xA9, 0x3, 0xE7, 0x88, 0x9B, 0x3, 0xE9, 0xBC, - 0x85, 0x3, 0xE4, 0x8D, 0x99, 0x3, 0xE5, 0xAA, 0xB5, 0x6, 0xE0, 0xB7, 0x99, - 0xE0, 0xB7, 0x8A, 0x4, 0xD7, 0xA7, 0xD6, 0xBC, 0x6, 0xCE, 0xB9, 0xCC, 0x93, - 0xCC, 0x81, 0x4, 0xF0, 0xA0, 0x95, 0x8B, 0x4, 0xF0, 0xA4, 0xB0, 0xB6, 0x4, - 0xF0, 0xA6, 0xB5, 0xAB, 0x3, 0xE9, 0x83, 0x8E, 0x3, 0xE7, 0x89, 0xA2, 0x3, - 0x4F, 0xCC, 0x84, 0x3, 0x65, 0xCC, 0x81, 0x3, 0x76, 0xCC, 0x83, 0x4, 0xCE, - 0xB1, 0xCC, 0x86, 0x4, 0xF0, 0xA8, 0x97, 0x92, 0x5, 0x65, 0xCC, 0x82, 0xCC, - 0x80, 0x2, 0xCC, 0x81, 0x3, 0x55, 0xCC, 0x81, 0x3, 0xE5, 0x80, 0xAB, 0x5, - 0x41, 0xCC, 0x82, 0xCC, 0x81, 0x4, 0xCE, 0xA9, 0xCD, 0x85, 0x5, 0x53, 0xCC, - 0x8C, 0xCC, 0x87, 0x5, 0x6F, 0xCC, 0x9B, 0xCC, 0x83, 0x3, 0x49, 0xCC, 0xA8, - 0x3, 0xE7, 0xA4, 0xAA, 0x4, 0xF0, 0xA4, 0xBE, 0xB8, 0x3, 0x64, 0xCC, 0xA3, - 0x6, 0xE0, 0xB5, 0x86, 0xE0, 0xB5, 0x97, 0x3, 0x42, 0xCC, 0xB1, 0x3, 0xE8, - 0xA1, 0xA0, 0x3, 0xE9, 0x9F, 0xBF, 0x3, 0xE7, 0x9D, 0x8A, 0x6, 0xCE, 0xB5, - 0xCC, 0x94, 0xCC, 0x80, 0x3, 0xE9, 0x8D, 0x8A, 0x3, 0xE6, 0xB5, 0xB7, 0x6, - 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0x3, 0xE3, 0x92, 0xBB, 0x3, 0xE7, 0xA3, - 0x8A, 0x3, 0xE6, 0xB8, 0x9A, 0x3, 0xE6, 0xB4, 0x9B, 0x3, 0xE9, 0xA0, 0xBB, - 0x5, 0x55, 0xCC, 0x9B, 0xCC, 0xA3, 0x3, 0xE5, 0x94, 0x90, 0x3, 0xE8, 0xAE, - 0x8A, 0x3, 0x6F, 0xCC, 0x91, 0x4, 0xCE, 0xB5, 0xCC, 0x81, 0x5, 0x65, 0xCC, - 0xA3, 0xCC, 0x82, 0x4, 0xCE, 0xA9, 0xCC, 0x81, 0x4, 0xC2, 0xA8, 0xCC, 0x80, - 0x3, 0xE7, 0xA5, 0x89, 0x3, 0xE9, 0xBA, 0x9F, 0x3, 0xE6, 0xB5, 0xAA, 0x3, - 0xE7, 0xB8, 0x82, 0x6, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x3, 0xE4, 0x8F, - 0x95, 0x3, 0x65, 0xCC, 0x8C, 0x3, 0xE7, 0xA3, 0x8C, 0x3, 0xE5, 0xB0, 0xBF, - 0x3, 0xE8, 0xBD, 0xA2, 0x3, 0xE8, 0xB1, 0x95, 0x5, 0xE2, 0x89, 0xB2, 0xCC, - 0xB8, 0x3, 0xE6, 0xB4, 0x9E, 0x8, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x82, 0xCD, - 0x85, 0x4, 0xCE, 0x91, 0xCC, 0x80, 0x3, 0xE5, 0xBB, 0x8A, 0x5, 0xE1, 0xBE, - 0xBF, 0xCC, 0x80, 0x4, 0xF0, 0xA3, 0x9A, 0xA3, 0x4, 0xF0, 0xA3, 0x8A, 0xB8, - 0x3, 0xE8, 0x8A, 0xB1, 0x5, 0x75, 0xCC, 0x84, 0xCC, 0x88, 0x3, 0xE5, 0xA0, - 0x8D, 0x3, 0xE5, 0xA8, 0x9B, 0x5, 0xE2, 0x8A, 0xAB, 0xCC, 0xB8, 0x4, 0xD7, - 0x9A, 0xD6, 0xBC, 0x3, 0x59, 0xCC, 0x82, 0x3, 0xE5, 0xB2, 0x8D, 0x3, 0x45, - 0xCC, 0x89, 0x3, 0xE9, 0x81, 0xB2, 0x3, 0xE8, 0xB4, 0x9B, 0x3, 0x75, 0xCC, - 0x83, 0x3, 0x4E, 0xCC, 0x81, 0x6, 0xE0, 0xBD, 0x91, 0xE0, 0xBE, 0xB7, 0x3, - 0x73, 0xCC, 0xA3, 0x3, 0xE6, 0xB5, 0x81, 0x3, 0xE9, 0xA0, 0x8B, 0x3, 0x4B, - 0xCC, 0xB1, 0x4, 0xF0, 0xA8, 0x97, 0xAD, 0x4, 0xCE, 0x91, 0xCD, 0x85, 0x3, - 0xE6, 0x84, 0x88, 0x3, 0xE7, 0x9B, 0x8A, 0x5, 0xE2, 0x89, 0xBD, 0xCC, 0xB8, - 0x3, 0xE9, 0x8F, 0xB9, 0x3, 0xE5, 0xBC, 0x84, 0x3, 0x61, 0xCC, 0x88, 0x3, - 0xE5, 0x87, 0x89, 0x3, 0xE9, 0x9B, 0xB6, 0x3, 0xE9, 0xBE, 0x9C, 0x3, 0x52, - 0xCC, 0xA7, 0x8, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x3, 0x4F, - 0xCC, 0x86, 0x3, 0xE6, 0x99, 0xB4, 0x8, 0xF0, 0x91, 0x96, 0xB9, 0xF0, 0x91, - 0x96, 0xAF, 0x3, 0x73, 0xCC, 0x82, 0x3, 0xE7, 0x85, 0x89, 0x3, 0xE4, 0xBE, - 0xAE, 0x5, 0x53, 0xCC, 0x81, 0xCC, 0x87, 0x3, 0xE6, 0xA7, 0xAA, 0x3, 0x53, - 0xCC, 0xA7, 0x3, 0x53, 0xCC, 0xA6, 0x3, 0xE9, 0x8C, 0x84, 0x4, 0xCF, 0x85, - 0xCC, 0x86, 0x4, 0xD0, 0xA3, 0xCC, 0x88, 0x3, 0xE8, 0x84, 0xBE, 0x6, 0xCF, - 0x85, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0xE6, 0xB4, 0xB4, 0x3, 0xE5, 0x88, 0xBA, - 0x3, 0xE5, 0x91, 0xA8, 0x3, 0x54, 0xCC, 0xA3, 0x3, 0xE8, 0x91, 0x97, 0x3, - 0xE5, 0xA0, 0xB1, 0x3, 0xE7, 0xAB, 0x8B, 0x4, 0xCE, 0xA5, 0xCC, 0x81, 0x3, - 0x48, 0xCC, 0xAE, 0x3, 0x62, 0xCC, 0x87, 0x3, 0x55, 0xCC, 0xA3, 0x5, 0x73, - 0xCC, 0x8C, 0xCC, 0x87, 0x3, 0xE5, 0x8F, 0x8A, 0x4, 0xCE, 0x97, 0xCC, 0x94, - 0x3, 0x47, 0xCC, 0x87, 0x3, 0xE5, 0xBA, 0xB6, 0x3, 0xE5, 0x85, 0xA9, 0x3, - 0xE8, 0x82, 0xAD, 0x3, 0xE8, 0x95, 0xA4, 0x3, 0xE8, 0xAB, 0xAD, 0x3, 0xE8, - 0x8F, 0x8C, 0x4, 0xCF, 0x89, 0xCC, 0x93, 0x3, 0xE5, 0xAF, 0x98, 0x6, 0xE3, - 0x81, 0xAF, 0xE3, 0x82, 0x9A, 0x3, 0xE8, 0x89, 0xAF, 0x6, 0xE3, 0x83, 0xB2, - 0xE3, 0x82, 0x99, 0x3, 0xE9, 0xBA, 0x97, 0x3, 0x72, 0xCC, 0xB1, 0x3, 0xE5, - 0x90, 0xB8, 0x3, 0xE7, 0x8D, 0xB5, 0x3, 0xE5, 0x8F, 0x83, 0x4, 0xCE, 0xB7, - 0xCC, 0x94, 0x3, 0x6B, 0xCC, 0xB1, 0x3, 0xE7, 0xB3, 0x92, 0x3, 0x67, 0xCC, - 0x86, 0x3, 0x75, 0xCC, 0x88, 0x3, 0xE9, 0x87, 0x8F, 0x3, 0xE6, 0xBD, 0xAE, - 0x3, 0xE9, 0x88, 0xB4, 0x4, 0xF0, 0xA6, 0x9E, 0xA7, 0x3, 0xE3, 0xBF, 0xBC, - 0x4, 0xF0, 0xA1, 0xAC, 0x98, 0x3, 0x41, 0xCC, 0x89, 0x4, 0xF0, 0xA7, 0xA5, - 0xA6, 0x3, 0xE7, 0xB4, 0x90, 0x3, 0xE7, 0x80, 0x9B, 0x3, 0xE5, 0x85, 0xAD, - 0x8, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x4, 0xD0, 0xB8, 0xCC, - 0x84, 0x3, 0xE8, 0x9E, 0xBA, 0x3, 0xE8, 0x9C, 0x8E, 0x3, 0xE6, 0xBF, 0xBE, - 0x3, 0xE4, 0x88, 0x82, 0x3, 0xE6, 0x9A, 0x91, 0x3, 0x6F, 0xCC, 0x81, 0x4, - 0xF0, 0xA9, 0xAC, 0xB0, 0x3, 0x79, 0xCC, 0x84, 0x3, 0x43, 0xCC, 0x8C, 0x4, - 0xD1, 0x8B, 0xCC, 0x88, 0x3, 0xE8, 0x8C, 0xB6, 0x4, 0xF0, 0xA6, 0x9E, 0xB5, - 0x5, 0x43, 0xCC, 0xA7, 0xCC, 0x81, 0x8, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, - 0xCD, 0x85, 0x3, 0xE7, 0xB8, 0xB7, 0x4, 0xD7, 0x96, 0xD6, 0xBC, 0x3, 0x48, - 0xCC, 0x82, 0x6, 0xE0, 0xBD, 0x82, 0xE0, 0xBE, 0xB7, 0x3, 0x68, 0xCC, 0xA3, - 0x3, 0x45, 0xCC, 0x88, 0x3, 0xE9, 0x84, 0x9B, 0x6, 0xCE, 0xA5, 0xCC, 0x94, - 0xCC, 0x81, 0x3, 0xE8, 0xA3, 0x9E, 0x3, 0x76, 0xCC, 0xA3, 0x3, 0xE8, 0x99, - 0x9C, 0x4, 0xD7, 0x9B, 0xD6, 0xBF, 0x5, 0x75, 0xCC, 0x9B, 0xCC, 0x83, 0x3, - 0x5A, 0xCC, 0xA3, 0x3, 0xE7, 0x94, 0xBE, 0x3, 0xE6, 0x8B, 0xBC, 0x3, 0xE5, - 0xA5, 0x91, 0x3, 0xE6, 0x9C, 0x97, 0x3, 0xE5, 0x96, 0xB3, 0x4, 0xC3, 0x98, - 0xCC, 0x81, 0x4, 0xCE, 0x95, 0xCC, 0x94, 0x6, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, - 0x82, 0x8, 0xF0, 0x91, 0x82, 0x99, 0xF0, 0x91, 0x82, 0xBA, 0x3, 0xE8, 0xA5, - 0xA4, 0x3, 0x41, 0xCC, 0x86, 0x3, 0xE5, 0x82, 0x99, 0x5, 0x6F, 0xCC, 0x82, - 0xCC, 0x83, 0x4, 0xF0, 0xA9, 0x87, 0x9F, 0x3, 0x47, 0xCC, 0x82, 0x6, 0xE0, - 0xAE, 0x92, 0xE0, 0xAF, 0x97, 0x5, 0x75, 0xCC, 0x9B, 0xCC, 0x80, 0x5, 0x75, - 0xCC, 0x88, 0xCC, 0x81, 0x6, 0xE1, 0xAC, 0x89, 0xE1, 0xAC, 0xB5, 0x3, 0x41, - 0xCC, 0x88, 0x4, 0xF0, 0xA2, 0xA1, 0x8A, 0x3, 0x45, 0xCC, 0xA8, 0x3, 0xE8, - 0x9E, 0x86, 0x3, 0xE6, 0x8C, 0xBD, 0x3, 0xE9, 0x9F, 0xA0, 0x3, 0xE5, 0xAF, - 0xB3, 0x3, 0xE5, 0x96, 0x99, 0x3, 0xE5, 0xAF, 0x83, 0x4, 0xCE, 0x95, 0xCC, - 0x80, 0x8, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x3, 0xE6, 0x8F, - 0xA4, 0x3, 0xE5, 0xA4, 0xA2, 0x8, 0xF0, 0x91, 0x8D, 0x87, 0xF0, 0x91, 0x8D, - 0x97, 0x3, 0x74, 0xCC, 0x8C, 0x3, 0xE4, 0x94, 0xAB, 0x3, 0x63, 0xCC, 0xA7, - 0x3, 0xE8, 0x88, 0x84, 0x3, 0xE5, 0x87, 0xB5, 0x3, 0xE7, 0xA3, 0xBB, 0x3, - 0x7A, 0xCC, 0x81, 0x4, 0xF0, 0xA5, 0x90, 0x9D, 0x3, 0xE5, 0xB5, 0x83, 0x3, - 0xE5, 0x92, 0xBD, 0x3, 0xE5, 0xB1, 0xA5, 0x3, 0x50, 0xCC, 0x81, 0x3, 0xE5, - 0xBE, 0xA9, 0x3, 0xE5, 0xB0, 0xA2, 0x5, 0x6F, 0xCC, 0x83, 0xCC, 0x81, 0x6, - 0xE1, 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0x4, 0xD3, 0x98, 0xCC, 0x88, 0x3, 0xE9, - 0x90, 0x95, 0x3, 0xE5, 0x83, 0x9A, 0x3, 0xE4, 0x88, 0xA7, 0x3, 0x75, 0xCC, - 0x8A, 0x3, 0xE7, 0x8E, 0x8B, 0x6, 0xE1, 0xAC, 0x85, 0xE1, 0xAC, 0xB5, 0x3, - 0x6A, 0xCC, 0x82, 0x3, 0xE6, 0x91, 0x92, 0x6, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, - 0x81, 0x3, 0x49, 0xCC, 0x86, 0x4, 0xCF, 0x92, 0xCC, 0x81, 0xC, 0xF0, 0x9D, - 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0x3, 0x52, 0xCC, - 0x8F, 0x4, 0xD0, 0x98, 0xCC, 0x88, 0x3, 0xE6, 0xBA, 0x9C, 0x3, 0xE3, 0xBA, - 0xB8, 0x5, 0x6F, 0xCC, 0x9B, 0xCC, 0x80, 0x8, 0xF0, 0x9D, 0x85, 0x97, 0xF0, - 0x9D, 0x85, 0xA5, 0x3, 0xE5, 0x95, 0xA3, 0x2, 0xCC, 0x93, 0x6, 0xCF, 0x85, - 0xCC, 0x93, 0xCD, 0x82, 0x3, 0xE5, 0x8A, 0x89, 0x9, 0xE0, 0xB3, 0x86, 0xE0, - 0xB3, 0x82, 0xE0, 0xB3, 0x95, 0x4, 0xF0, 0xA1, 0x9A, 0xA8, 0x3, 0x75, 0xCC, - 0x8B, 0x3, 0x63, 0xCC, 0x8C, 0x3, 0xE8, 0xA4, 0x90, 0x3, 0xE8, 0x8D, 0x93, - 0x3, 0xE5, 0xBA, 0xB0, 0x3, 0x6F, 0xCC, 0x9B, 0x3, 0xE5, 0xAF, 0xA7, 0x3, - 0xE5, 0x86, 0xB5, 0x3, 0xE9, 0x83, 0x9E, 0x5, 0xE2, 0x88, 0x8B, 0xCC, 0xB8, - 0x3, 0x68, 0xCC, 0x82, 0x3, 0xE8, 0xA6, 0x8B, 0x6, 0xCE, 0xA5, 0xCC, 0x94, - 0xCD, 0x82, 0x6, 0xE1, 0x80, 0xA5, 0xE1, 0x80, 0xAE, 0x3, 0xE9, 0xA1, 0x9E, - 0x3, 0xE5, 0xA5, 0x94, 0x3, 0x5A, 0xCC, 0x87, 0x3, 0xE7, 0x88, 0xA8, 0x8, - 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0x5, 0x41, 0xCC, 0xA3, 0xCC, - 0x86, 0x3, 0xE3, 0xA8, 0xAE, 0x3, 0x4B, 0xCC, 0x8C, 0x6, 0xE0, 0xAF, 0x86, - 0xE0, 0xAE, 0xBE, 0x3, 0xE5, 0x85, 0xA7, 0x4, 0xD0, 0x98, 0xCC, 0x84, 0x6, - 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x82, 0x6, 0xE0, 0xBD, 0xB1, 0xE0, 0xBD, 0xB2, - 0x3, 0xE7, 0x85, 0xAE, 0x6, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81, 0x5, 0x6F, - 0xCC, 0x82, 0xCC, 0x89, 0x4, 0xF0, 0xA7, 0xB2, 0xA8, 0x5, 0x49, 0xCC, 0x88, - 0xCC, 0x81, 0x6, 0xE0, 0xAD, 0x87, 0xE0, 0xAC, 0xBE, 0x6, 0xCF, 0x85, 0xCC, - 0x94, 0xCC, 0x80, 0x4, 0xCE, 0x95, 0xCC, 0x81, 0x3, 0xE9, 0x99, 0x8D, 0x3, - 0xE9, 0x9A, 0x86, 0x4, 0xF0, 0xA5, 0x84, 0xB3, 0x4, 0xD7, 0x9C, 0xD6, 0xBC, - 0x3, 0xE5, 0xA3, 0xB7, 0x3, 0x3D, 0xCC, 0xB8, 0x4, 0xDB, 0x92, 0xD9, 0x94, - 0x8, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x4, 0xCE, 0xB9, 0xCD, - 0x82, 0x3, 0xE4, 0xB3, 0x8E, 0x6, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0x3, - 0x55, 0xCC, 0x9B, 0x5, 0x6F, 0xCC, 0x9B, 0xCC, 0xA3, 0x3, 0xE8, 0x99, 0x90, - 0x8, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85, 0xA5, 0x4, 0xD8, 0xA7, 0xD9, - 0x93, 0x6, 0xE0, 0xBD, 0x8C, 0xE0, 0xBE, 0xB7, 0x3, 0x70, 0xCC, 0x81, 0x3, - 0xE8, 0xBC, 0xBB, 0x4, 0xF0, 0xA0, 0x84, 0xA2, 0x3, 0x55, 0xCC, 0x8F, 0x3, - 0xE9, 0x98, 0xAE, 0x3, 0xE4, 0xB8, 0xB9, 0x5, 0x61, 0xCC, 0x82, 0xCC, 0x80, - 0x3, 0xE5, 0xA3, 0xB2, 0x3, 0x57, 0xCC, 0x87, 0x6, 0xE3, 0x81, 0x9B, 0xE3, - 0x82, 0x99, 0x4, 0xD1, 0x87, 0xCC, 0x88, 0x3, 0xE7, 0xBE, 0xBD, 0x3, 0x75, - 0xCC, 0x80, 0x3, 0x6E, 0xCC, 0xA3, 0x3, 0xE5, 0x86, 0xA4, 0x3, 0x47, 0xCC, - 0x8C, 0x3, 0xE6, 0xB7, 0xB9, 0x4, 0xCE, 0xB1, 0xCC, 0x94, 0x4, 0xD0, 0xAB, - 0xCC, 0x88, 0x3, 0x69, 0xCC, 0x86, 0x5, 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, 0x3, - 0x4D, 0xCC, 0xA3, 0x3, 0x79, 0xCC, 0x8A, 0x5, 0x6F, 0xCC, 0x83, 0xCC, 0x88, - 0x3, 0x48, 0xCC, 0x88, 0x4, 0xD1, 0x8D, 0xCC, 0x88, 0x4, 0xF0, 0xA7, 0x99, - 0xA7, 0x3, 0xE5, 0xBA, 0xB3, 0x5, 0xE2, 0x8A, 0xB4, 0xCC, 0xB8, 0x3, 0x53, - 0xCC, 0xA3, 0x5, 0x65, 0xCC, 0x82, 0xCC, 0x83, 0x3, 0xE5, 0xA3, 0xAE, 0x3, - 0xE7, 0xA5, 0x9E, 0x1, 0x4B, 0x6, 0xE3, 0x81, 0x91, 0xE3, 0x82, 0x99, 0x6, - 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0x3, 0x53, 0xCC, 0x87, 0x3, 0xE6, 0xBF, - 0x86, 0x3, 0xE9, 0x9A, 0xA3, 0x6, 0xE0, 0xB1, 0x86, 0xE0, 0xB1, 0x96, 0x3, - 0xE6, 0x95, 0x96, 0x8, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x3, - 0xE9, 0xB5, 0xA7, 0x3, 0xE5, 0xA7, 0xAC, 0x3, 0xE5, 0x85, 0x8D, 0x3, 0x4E, - 0xCC, 0x83, 0x5, 0x61, 0xCC, 0x87, 0xCC, 0x84, 0x3, 0xE6, 0xBB, 0x91, 0x3, - 0xE7, 0x88, 0x90, 0x3, 0xE8, 0x8F, 0x8A, 0x4, 0xCE, 0x99, 0xCC, 0x88, 0xC, - 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0x6, - 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0x3, 0xE9, 0xBC, 0x96, 0x3, 0xE8, 0x8F, - 0xAF, 0x3, 0x77, 0xCC, 0x80, 0x6, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0x4, - 0xF0, 0xA6, 0x88, 0xA8, 0x4, 0xD7, 0x90, 0xD6, 0xBC, 0x5, 0x45, 0xCC, 0x82, - 0xCC, 0x81, 0x3, 0xE7, 0xA8, 0x9C, 0x3, 0x64, 0xCC, 0x8C, 0x4, 0xCE, 0x9F, - 0xCC, 0x93, 0x3, 0xE7, 0x97, 0xA2, 0x3, 0xE6, 0xA2, 0xA8, 0x5, 0x41, 0xCC, - 0x87, 0xCC, 0x84, 0x4, 0xD0, 0x97, 0xCC, 0x88, 0x6, 0xE3, 0x81, 0x99, 0xE3, - 0x82, 0x99, 0x5, 0x61, 0xCC, 0x8A, 0xCC, 0x81, 0x3, 0xE6, 0x9A, 0x88, 0x3, - 0xE6, 0x83, 0x98, 0x4, 0xCE, 0xA5, 0xCC, 0x80, 0x4, 0xF0, 0xA0, 0xA3, 0x9E, - 0x4, 0xD7, 0xAA, 0xD6, 0xBC, 0x6, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x80, 0x3, - 0xE6, 0xB6, 0x85, 0x4, 0xF0, 0xA7, 0x8F, 0x8A, 0x6, 0xE1, 0xAC, 0xBE, 0xE1, - 0xAC, 0xB5, 0x3, 0xE6, 0x82, 0x81, 0x3, 0xE9, 0xB6, 0xB4, 0x3, 0xE5, 0x8F, - 0x9F, 0x3, 0xE5, 0x86, 0x80, 0x3, 0xE5, 0x91, 0x88, 0x3, 0x69, 0xCC, 0xA3, - 0x5, 0x4F, 0xCC, 0xA3, 0xCC, 0x82, 0x3, 0xE5, 0xA8, 0xA7, 0x3, 0x44, 0xCC, - 0xAD, 0x3, 0xE6, 0x91, 0xA9, 0x3, 0xE6, 0x89, 0x9D, 0x5, 0x4F, 0xCC, 0x9B, - 0xCC, 0xA3, 0x3, 0x45, 0xCC, 0x80, 0x4, 0xF0, 0xA4, 0xA0, 0x94, 0x1, 0x3B, - 0x3, 0x54, 0xCC, 0xAD, 0x5, 0xE2, 0x89, 0x8D, 0xCC, 0xB8, 0x6, 0xCF, 0x89, - 0xCC, 0x94, 0xCD, 0x82, 0x3, 0xE6, 0x86, 0x90, 0x3, 0x74, 0xCC, 0xA6, 0x3, - 0xE9, 0xAC, 0x92, 0x4, 0xF0, 0xA0, 0x94, 0xA5, 0x3, 0xE7, 0xA2, 0x91, 0x6, - 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80, 0x4, 0xD1, 0x96, 0xCC, 0x88, 0x3, 0xE7, - 0xA1, 0xAB, 0x6, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x9A, 0x3, 0x42, 0xCC, 0x87, - 0x5, 0x55, 0xCC, 0x88, 0xCC, 0x80, 0x3, 0xE5, 0xA9, 0xA6, 0x4, 0xF0, 0xA5, - 0x98, 0xA6, 0x3, 0xE9, 0x83, 0xB1, 0x3, 0xE5, 0x99, 0xB4, 0x3, 0xE7, 0xA6, - 0x8F, 0x3, 0xE7, 0x8E, 0xA5, 0x4, 0xCE, 0xB1, 0xCC, 0x81, 0x3, 0xE5, 0x8C, - 0x85, 0x3, 0xE8, 0xBC, 0xAA, 0x3, 0xE7, 0x91, 0xA9, 0x6, 0xE3, 0x81, 0xB5, - 0xE3, 0x82, 0x9A, 0x3, 0xE5, 0x8D, 0xB5, 0x6, 0xE0, 0xA8, 0x9C, 0xE0, 0xA8, - 0xBC, 0x6, 0xCE, 0xB1, 0xCC, 0x81, 0xCD, 0x85, 0x3, 0x47, 0xCC, 0x86, 0x4, - 0xD1, 0x83, 0xCC, 0x8B, 0x3, 0x52, 0xCC, 0x91, 0x3, 0xE9, 0xBB, 0xBE, 0x5, - 0xE2, 0x86, 0x92, 0xCC, 0xB8, 0x4, 0xCE, 0xB5, 0xCC, 0x80, 0x3, 0xE7, 0x8F, - 0x9E, 0x3, 0xE5, 0x81, 0xBA, 0x4, 0xF0, 0xAA, 0x98, 0x80, 0x4, 0xCE, 0x97, - 0xCC, 0x80, 0x6, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0x6, 0xCE, 0xB1, 0xCC, - 0x93, 0xCC, 0x80, 0x3, 0xE8, 0x8E, 0xBD, 0x4, 0xCA, 0x92, 0xCC, 0x8C, 0x4, - 0xD1, 0x83, 0xCC, 0x84, 0x6, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0x3, 0x79, - 0xCC, 0x80, 0x3, 0xE6, 0xAE, 0xBB, 0x3, 0x75, 0xCC, 0x82, 0x6, 0xE3, 0x81, - 0x8F, 0xE3, 0x82, 0x99, 0x5, 0xE2, 0x88, 0x83, 0xCC, 0xB8, 0x3, 0x54, 0xCC, - 0xA6, 0x3, 0xE5, 0x9F, 0xB4, 0x3, 0xE5, 0xAC, 0x88, 0x1, 0x60, 0x6, 0xE3, - 0x81, 0xAF, 0xE3, 0x82, 0x99, 0x6, 0xD7, 0xA9, 0xD6, 0xBC, 0xD7, 0x82, 0x4, - 0xF0, 0xA3, 0xAB, 0xBA, 0x3, 0xE5, 0x90, 0x9D, 0x3, 0xE5, 0xBB, 0x92, 0x3, - 0xE6, 0x9B, 0x86, 0x3, 0x61, 0xCC, 0x8F, 0x3, 0xE6, 0x8F, 0x85, 0x3, 0xE5, - 0x96, 0x84, 0x4, 0xCF, 0x89, 0xCD, 0x82, 0x3, 0xE4, 0x90, 0x8B, 0x5, 0x41, - 0xCC, 0x88, 0xCC, 0x84, 0x3, 0xE6, 0xB4, 0xBE, 0x6, 0xCF, 0x89, 0xCC, 0x93, - 0xCD, 0x82, 0x3, 0xE6, 0x88, 0x90, 0x4, 0xCE, 0x97, 0xCC, 0x93, 0x3, 0xE7, - 0x92, 0x89, 0x4, 0xF0, 0xA3, 0xA2, 0xA7, 0x3, 0xE6, 0x95, 0xB8, 0x3, 0xE8, - 0x8A, 0x8B, 0x3, 0xE7, 0x8A, 0x80, 0x4, 0xD0, 0xB5, 0xCC, 0x88, 0x3, 0xE8, - 0x81, 0xB0, 0x3, 0x6C, 0xCC, 0xA3, 0x3, 0xE5, 0x8B, 0x89, 0x3, 0x49, 0xCC, - 0xB0, 0x3, 0x77, 0xCC, 0x8A, 0x3, 0x49, 0xCC, 0x83, 0x3, 0x45, 0xCC, 0x84, - 0x3, 0x61, 0xCC, 0xA3, 0x3, 0x57, 0xCC, 0x80, 0x3, 0xE8, 0x8C, 0x9D, 0x5, - 0xE2, 0x88, 0xA5, 0xCC, 0xB8, 0x6, 0xE0, 0xBE, 0xA1, 0xE0, 0xBE, 0xB7, 0x3, - 0x55, 0xCC, 0x82, 0x5, 0x61, 0xCC, 0xA3, 0xCC, 0x86, 0x5, 0xE2, 0x8A, 0x87, - 0xCC, 0xB8, 0x3, 0xE9, 0x96, 0xAD, 0x3, 0xE5, 0x88, 0xBB, 0x3, 0x6F, 0xCC, - 0x87, 0x4, 0xCF, 0x85, 0xCC, 0x84, 0x3, 0xE6, 0xBA, 0xBA, 0x4, 0xF0, 0xA3, - 0x8F, 0x95, 0x4, 0xD7, 0x91, 0xD6, 0xBC, 0x4, 0xD0, 0xB6, 0xCC, 0x88, 0x4, - 0xCE, 0xA5, 0xCC, 0x94, 0x5, 0xE2, 0x8A, 0xB3, 0xCC, 0xB8, 0x5, 0x6F, 0xCC, - 0x84, 0xCC, 0x80, 0x3, 0x6F, 0xCC, 0x88, 0x3, 0xE5, 0xA5, 0x88, 0x3, 0xE9, - 0xA3, 0xAF, 0x4, 0xD0, 0xB5, 0xCC, 0x86, 0x3, 0xE5, 0x9C, 0x96, 0x5, 0x61, - 0xCC, 0x82, 0xCC, 0x89, 0x3, 0xE8, 0xB4, 0x88, 0x3, 0xE7, 0xBE, 0x85, 0x5, - 0x41, 0xCC, 0x86, 0xCC, 0x80, 0x3, 0xE3, 0x80, 0x88, 0x5, 0xE2, 0x87, 0x90, - 0xCC, 0xB8, 0x3, 0xE5, 0xBB, 0xBE, 0x5, 0x6F, 0xCC, 0x84, 0xCC, 0x81, 0x5, - 0x6F, 0xCC, 0x87, 0xCC, 0x84, 0x3, 0x75, 0xCC, 0xA8, 0x3, 0x59, 0xCC, 0x88, - 0x6, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0x41, 0xCC, 0x8A, 0x6, 0xCE, - 0xB7, 0xCD, 0x82, 0xCD, 0x85, 0x6, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x81, 0x3, - 0xE7, 0xAC, 0xA0, 0x3, 0xE5, 0xBB, 0xAC, 0x3, 0xE9, 0xB3, 0xBD, 0x3, 0xE7, - 0x8B, 0xBC, 0x3, 0xE3, 0xB4, 0xB3, 0x5, 0x65, 0xCC, 0xA7, 0xCC, 0x86, 0x3, - 0xE7, 0x8A, 0x95, 0x3, 0xE7, 0x89, 0x90, 0x3, 0xE3, 0x92, 0xB9, 0x3, 0x79, - 0xCC, 0x87, 0x5, 0x4F, 0xCC, 0x88, 0xCC, 0x84, 0x3, 0x49, 0xCC, 0x88, 0x3, - 0xE9, 0xA4, 0xA9, 0x8, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x4, - 0xCE, 0xBF, 0xCC, 0x94, 0x3, 0xE9, 0x9B, 0xA3, 0x4, 0xCE, 0xBF, 0xCC, 0x93, - 0x6, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x85, 0x3, 0xE7, 0xB7, 0x87, 0x3, 0xE8, - 0x9F, 0xA1, 0x4, 0xF0, 0xA0, 0x98, 0xBA, 0x3, 0xE5, 0x99, 0x91, 0x3, 0xE8, - 0xB3, 0x82, 0x3, 0x6C, 0xCC, 0x81, 0x3, 0x4F, 0xCC, 0x8F, 0x4, 0xD0, 0x95, - 0xCC, 0x80, 0x4, 0xD7, 0x90, 0xD6, 0xB7, 0x3, 0x4C, 0xCC, 0xB1, 0x4, 0xD7, - 0x91, 0xD6, 0xBF, 0x8, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0x6, - 0xE0, 0xA4, 0xAB, 0xE0, 0xA4, 0xBC, 0x6, 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99, - 0x3, 0xE7, 0xA9, 0x8F, 0x3, 0xE6, 0x8D, 0x90, 0x3, 0xE8, 0x9B, 0xA2, 0x8, - 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x3, 0xE5, 0x99, 0xA8, 0x3, - 0xE8, 0xA1, 0xA3, 0x3, 0x4E, 0xCC, 0xA3, 0x3, 0xE8, 0xAC, 0x81, 0x3, 0x72, - 0xCC, 0x91, 0x4, 0xD7, 0xA9, 0xD7, 0x81, 0x3, 0x74, 0xCC, 0xA3, 0x4, 0xF0, - 0xA5, 0x89, 0x89, 0x3, 0x69, 0xCC, 0x80, 0x6, 0xE3, 0x81, 0xA8, 0xE3, 0x82, - 0x99, 0x3, 0x41, 0xCC, 0x80, 0x3, 0xE8, 0xAC, 0xB9, 0x3, 0xE5, 0x8F, 0xAB, - 0x3, 0xE9, 0xA9, 0xAA, 0x3, 0x68, 0xCC, 0x88, 0x3, 0x78, 0xCC, 0x88, 0x6, - 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x3, 0xE5, 0xB7, 0xA1, 0x6, 0xCE, 0xB9, - 0xCC, 0x88, 0xCC, 0x80, 0x3, 0xE3, 0x9E, 0x81, 0x4, 0xCE, 0x9F, 0xCC, 0x94, - 0x6, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0x67, 0xCC, 0xA7, 0x4, 0xD0, - 0xB7, 0xCC, 0x88, 0x3, 0xE6, 0xAD, 0x94, 0x3, 0x43, 0xCC, 0x87, 0x3, 0x4C, - 0xCC, 0xA7, 0x6, 0xE3, 0x83, 0x84, 0xE3, 0x82, 0x99, 0x3, 0xE6, 0x85, 0x8C, - 0x5, 0x45, 0xCC, 0x82, 0xCC, 0x80, 0x4, 0xD7, 0xA6, 0xD6, 0xBC, 0x3, 0xE5, - 0xB1, 0xA0, 0x6, 0xE0, 0xBE, 0x92, 0xE0, 0xBE, 0xB7, 0x3, 0xE5, 0xBF, 0x8D, - 0x4, 0xF0, 0xA0, 0xAD, 0xA3, 0x3, 0x6E, 0xCC, 0x87, 0x4, 0xC3, 0xA6, 0xCC, - 0x81, 0x6, 0xE0, 0xAC, 0xA2, 0xE0, 0xAC, 0xBC, 0x4, 0xD0, 0xBA, 0xCC, 0x81, - 0x3, 0xE6, 0xBB, 0x87, 0x5, 0xE2, 0x86, 0x90, 0xCC, 0xB8, 0x4, 0xCE, 0xB7, - 0xCD, 0x85, 0x3, 0x65, 0xCC, 0x8F, 0x5, 0xE2, 0x86, 0x94, 0xCC, 0xB8, 0x3, - 0xE5, 0xAF, 0xBF, 0x3, 0x55, 0xCC, 0x83, 0x3, 0x79, 0xCC, 0x88, 0xC, 0xF0, - 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0x3, 0xE7, - 0xB3, 0xA8, 0x4, 0xF0, 0xA8, 0xAF, 0xBA, 0x3, 0xE5, 0xB9, 0xA9, 0x3, 0x75, - 0xCC, 0x84, 0x3, 0xE7, 0xA5, 0x96, 0x3, 0x6C, 0xCC, 0xA7, 0x5, 0x6C, 0xCC, - 0xA3, 0xCC, 0x84, 0x3, 0x45, 0xCC, 0x81, 0x3, 0x74, 0xCC, 0x87, 0x3, 0xE6, - 0xBB, 0x8B, 0x4, 0xCE, 0x97, 0xCC, 0x81, 0x3, 0x6F, 0xCC, 0x8C, 0x3, 0xE7, - 0x9B, 0xA7, 0x3, 0x77, 0xCC, 0xA3, 0x3, 0xE6, 0x90, 0xA2, 0x8, 0xF0, 0x91, - 0x84, 0xB1, 0xF0, 0x91, 0x84, 0xA7, 0x6, 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99, - 0x3, 0x56, 0xCC, 0x83, 0x3, 0x55, 0xCC, 0x86, 0x5, 0xE2, 0x8A, 0x91, 0xCC, - 0xB8, 0x8, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x6, 0xCE, 0xB7, - 0xCC, 0x94, 0xCD, 0x85, 0x4, 0xF0, 0xA5, 0x9B, 0x85, 0x3, 0x59, 0xCC, 0xA3, - 0x3, 0x67, 0xCC, 0x8C, 0x3, 0x65, 0xCC, 0xA8, 0x3, 0xE5, 0xB1, 0xA4, 0x3, - 0xE8, 0x8A, 0xB3, 0x6, 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0x3, 0xE6, 0x87, - 0x9E, 0x6, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85, 0x3, 0xE4, 0xB3, 0xAD, 0x8, - 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x3, 0x41, 0xCC, 0x82, 0x3, - 0xE4, 0xB8, 0xA6, 0x4, 0xF0, 0xA5, 0xAE, 0xAB, 0x6, 0xE3, 0x81, 0xB2, 0xE3, - 0x82, 0x9A, 0x3, 0xE9, 0x81, 0xBC, 0x3, 0xE5, 0x98, 0x86, 0x4, 0xCF, 0x85, - 0xCC, 0x80, 0x4, 0xD7, 0xA0, 0xD6, 0xBC, 0x3, 0xE7, 0xA5, 0x88, 0x3, 0x4F, - 0xCC, 0x81, 0x3, 0xE4, 0xAF, 0x8E, 0x3, 0xE5, 0xA9, 0xA2, 0x3, 0xE5, 0xBA, - 0xA6, 0x3, 0xE7, 0x80, 0xB9, 0x6, 0xE1, 0xAC, 0x87, 0xE1, 0xAC, 0xB5, 0x3, - 0xE6, 0x80, 0x92, 0x3, 0xE6, 0x9D, 0x96, 0x3, 0xE5, 0xA2, 0xAC, 0x3, 0x61, - 0xCC, 0x8C, 0x3, 0x49, 0xCC, 0x80, 0x3, 0x75, 0xCC, 0xA4, 0x3, 0xE7, 0xB1, - 0xA0, 0x4, 0xF0, 0xA6, 0x96, 0xA8, 0x4, 0xCE, 0x99, 0xCC, 0x84, 0x4, 0xF0, - 0xA2, 0x86, 0x83, 0x3, 0xE7, 0x88, 0xB5, 0x3, 0xE5, 0x8C, 0x97, 0x6, 0xE3, - 0x83, 0xAF, 0xE3, 0x82, 0x99, 0x3, 0xE6, 0xAC, 0x84, 0x3, 0xE5, 0x86, 0xAC, - 0x3, 0xE5, 0x80, 0x82, 0x3, 0xE7, 0xB4, 0xAF, 0x3, 0x75, 0xCC, 0x91, 0x3, - 0xE6, 0xAC, 0xA1, 0x3, 0xE7, 0xAF, 0x80, 0x3, 0xE9, 0x86, 0xB4, 0x3, 0xE5, - 0xA1, 0x9A, 0x3, 0xE9, 0xA0, 0x98, 0x5, 0xE2, 0x88, 0x88, 0xCC, 0xB8, 0x5, - 0x6F, 0xCC, 0xA3, 0xCC, 0x82, 0x6, 0xD7, 0xA9, 0xD6, 0xBC, 0xD7, 0x81, 0x4, - 0xCF, 0x85, 0xCD, 0x82, 0x4, 0xF0, 0xAA, 0x88, 0x8E, 0x5, 0x45, 0xCC, 0x82, - 0xCC, 0x83, 0x6, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0x5, 0x75, 0xCC, 0x9B, - 0xCC, 0x89, 0x3, 0xE7, 0xAA, 0xB1, 0x4, 0xCE, 0xB1, 0xCC, 0x84, 0x3, 0xE6, - 0x97, 0xA2, 0x3, 0xE8, 0xA0, 0x9F, 0xC, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, - 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB2, 0x4, 0xCE, 0xA9, 0xCC, 0x80, 0x3, 0xE4, - 0xBA, 0x86, 0x6, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x81, 0x4, 0xF0, 0xA3, 0xBE, - 0x8E, 0x6, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x85, 0x3, 0x65, 0xCC, 0x80, 0x8, - 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x5, 0xE2, 0x89, 0x85, 0xCC, - 0xB8, 0x4, 0xF0, 0xA7, 0xBB, 0x93, 0x3, 0x6E, 0xCC, 0xB1, 0x3, 0xE8, 0x87, - 0xA8, 0x5, 0xE2, 0x89, 0x88, 0xCC, 0xB8, 0x3, 0x62, 0xCC, 0xB1, 0x5, 0xE2, - 0x8A, 0x82, 0xCC, 0xB8, 0x6, 0xCE, 0xB9, 0xCC, 0x94, 0xCD, 0x82, 0x3, 0xE7, - 0xA6, 0x8D, 0x3, 0x77, 0xCC, 0x88, 0x3, 0x6E, 0xCC, 0xAD, 0x3, 0xE8, 0xBC, - 0xB8, 0x3, 0x44, 0xCC, 0xB1, 0x3, 0xE5, 0x89, 0x86, 0x4, 0xF0, 0xA5, 0x84, - 0x99, 0x3, 0xE7, 0x92, 0x85, 0x3, 0xE7, 0xA7, 0xAB, 0x4, 0xF0, 0xA6, 0x93, - 0x9A, 0x3, 0xE7, 0xA9, 0x80, 0x5, 0x41, 0xCC, 0x82, 0xCC, 0x83, 0x3, 0xE6, - 0xBC, 0xA2, 0x5, 0x4F, 0xCC, 0x83, 0xCC, 0x84, 0x3, 0xE3, 0xA3, 0x87, 0x6, - 0xE0, 0xBD, 0xB1, 0xE0, 0xBD, 0xB4, 0x3, 0x6B, 0xCC, 0xA7, 0x3, 0x72, 0xCC, - 0x87, 0x4, 0xF0, 0xA5, 0xB3, 0x90, 0x6, 0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99, - 0x4, 0xD0, 0x96, 0xCC, 0x88, 0x3, 0x55, 0xCC, 0x8A, 0x3, 0xE8, 0x82, 0xB2, - 0x3, 0x61, 0xCC, 0xA5, 0x4, 0xCF, 0x92, 0xCC, 0x88, 0x3, 0xE6, 0x98, 0x93, - 0x3, 0x74, 0xCC, 0xB1, 0x6, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0xE5, - 0xB8, 0xA8, 0x8, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x3, 0xE5, - 0xBF, 0xB5, 0x3, 0x6F, 0xCC, 0x86, 0x3, 0xE5, 0x83, 0xA7, 0x3, 0xE4, 0x9A, - 0xBE, 0x3, 0xE7, 0x8B, 0x80, 0x5, 0x6F, 0xCC, 0x9B, 0xCC, 0x89, 0x4, 0xF0, - 0xA3, 0xAA, 0x8D, 0x3, 0xE6, 0xBC, 0xA3, 0x3, 0x41, 0xCC, 0xA3, 0x3, 0x65, - 0xCC, 0xB0, 0x3, 0xE7, 0xA5, 0xA5, 0x8, 0xF0, 0x91, 0x82, 0x9B, 0xF0, 0x91, - 0x82, 0xBA, 0x3, 0x59, 0xCC, 0x89, 0x3, 0xE5, 0x8A, 0xA3, 0x8, 0xCE, 0xB1, - 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE6, 0x85, 0x84, 0x4, 0xD0, 0xA7, - 0xCC, 0x88, 0x3, 0x4F, 0xCC, 0xA3, 0x4, 0xD0, 0xB8, 0xCC, 0x88, 0x3, 0x6B, - 0xCC, 0x8C, 0x5, 0x45, 0xCC, 0x84, 0xCC, 0x81, 0x3, 0xE4, 0x82, 0x96, 0x3, - 0xE6, 0x9A, 0xB4, 0x4, 0xF0, 0xAA, 0x8E, 0x92, 0x3, 0xE9, 0x99, 0xB5, 0x6, - 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x81, 0x4, 0xD3, 0x99, 0xCC, 0x88, 0x3, 0xE8, - 0x84, 0x83, 0x3, 0xE9, 0xB8, 0x9E, 0x3, 0x75, 0xCC, 0x89, 0x5, 0xE1, 0xBE, - 0xBF, 0xCD, 0x82, 0x3, 0xE6, 0x85, 0x8E, 0x4, 0xF0, 0xA4, 0x98, 0x88, 0x3, - 0x61, 0xCC, 0x82, 0x3, 0xE8, 0xA0, 0x81, 0x4, 0xF0, 0xA1, 0xA7, 0x88, 0x3, - 0x5A, 0xCC, 0x81, 0x5, 0xE2, 0x87, 0x94, 0xCC, 0xB8, 0x4, 0xC3, 0x86, 0xCC, - 0x84, 0x6, 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0x6, 0xE3, 0x82, 0xB5, 0xE3, - 0x82, 0x99, 0x3, 0xE7, 0xA1, 0x8E, 0x3, 0x65, 0xCC, 0x82, 0x6, 0xE3, 0x81, - 0x8B, 0xE3, 0x82, 0x99, 0x6, 0xE1, 0xAC, 0xBA, 0xE1, 0xAC, 0xB5, 0x3, 0xE4, - 0xB3, 0xB8, 0x4, 0xD0, 0xB6, 0xCC, 0x86, 0x3, 0xE4, 0xB8, 0xBD, 0x3, 0x72, - 0xCC, 0xA3, 0x5, 0xE2, 0x8A, 0x83, 0xCC, 0xB8, 0x3, 0xE7, 0x83, 0x88, 0x3, - 0xE7, 0x98, 0x9D, 0x3, 0x61, 0xCC, 0x89, 0x5, 0x75, 0xCC, 0x9B, 0xCC, 0xA3, - 0x3, 0xE3, 0x9B, 0xBC, 0x3, 0xE4, 0xB9, 0x81, 0x6, 0xE0, 0xA8, 0x96, 0xE0, - 0xA8, 0xBC, 0x3, 0x48, 0xCC, 0x8C, 0x3, 0x57, 0xCC, 0x82, 0x3, 0x6D, 0xCC, - 0x87, 0x3, 0xE5, 0xBE, 0x9A, 0x3, 0xE4, 0x8C, 0x81, 0x3, 0xE9, 0xBD, 0x83, - 0x4, 0xCE, 0xA1, 0xCC, 0x94, 0x3, 0xE5, 0x85, 0x85, 0x4, 0xF0, 0xA5, 0x83, - 0xB3, 0x3, 0x45, 0xCC, 0xB0, 0x4, 0xCF, 0x89, 0xCD, 0x85, 0x6, 0xCE, 0xA5, - 0xCC, 0x94, 0xCC, 0x80, 0x3, 0xE6, 0x8B, 0xBE, 0x3, 0xE5, 0x95, 0x93, 0x3, - 0xE7, 0x8D, 0xBA, 0x3, 0x49, 0xCC, 0x8F, 0x3, 0xE3, 0xAC, 0x88, 0x3, 0x55, - 0xCC, 0xA4, 0x3, 0xE8, 0xB3, 0x81, 0x4, 0xCE, 0x99, 0xCC, 0x80, 0x3, 0xE6, - 0x92, 0x9D, 0x3, 0xE8, 0x88, 0x81, 0x3, 0xE6, 0xA2, 0x8E, 0x3, 0xE8, 0x9C, - 0xA8, 0x4, 0xD0, 0x86, 0xCC, 0x88, 0x4, 0xCE, 0xB9, 0xCC, 0x94, 0x6, 0xE3, - 0x81, 0xB5, 0xE3, 0x82, 0x99, 0x5, 0xE2, 0x8A, 0x92, 0xCC, 0xB8, 0x3, 0xE5, - 0xA5, 0xA2, 0x3, 0xE6, 0x8B, 0x94, 0x3, 0xE5, 0x8B, 0x92, 0x3, 0xE6, 0xAD, - 0xB9, 0x3, 0x52, 0xCC, 0x81, 0x4, 0xD7, 0x9E, 0xD6, 0xBC, 0x3, 0xE5, 0x88, - 0x97, 0x4, 0xD8, 0xA7, 0xD9, 0x94, 0x3, 0xE5, 0x97, 0x80, 0x3, 0x61, 0xCC, - 0x91, 0x3, 0xE7, 0xBC, 0xBE, 0x4, 0xF0, 0xA3, 0x8D, 0x9F, 0x3, 0x67, 0xCC, - 0x87, 0x3, 0x68, 0xCC, 0xB1, 0x3, 0xE8, 0xA3, 0x8F, 0x3, 0xE5, 0xBD, 0xAB, - 0x5, 0xE2, 0x88, 0xA3, 0xCC, 0xB8, 0x6, 0xE0, 0xA8, 0x97, 0xE0, 0xA8, 0xBC, - 0x3, 0x57, 0xCC, 0x81, 0x3, 0xE6, 0xB7, 0x9A, 0x3, 0x4F, 0xCC, 0x8B, 0x3, - 0xE3, 0xA0, 0xAF, 0x3, 0xE6, 0x81, 0xB5, 0x4, 0xCE, 0xB9, 0xCC, 0x88, 0x3, - 0x53, 0xCC, 0x82, 0x3, 0xE3, 0xA3, 0xA3, 0x3, 0x6E, 0xCC, 0x8C, 0x6, 0xCE, - 0xB5, 0xCC, 0x93, 0xCC, 0x80, 0x3, 0xE9, 0x9A, 0xB8, 0x4, 0xD7, 0x93, 0xD6, - 0xBC, 0x2, 0xCA, 0xB9, 0x3, 0xE5, 0xBF, 0xB9, 0x6, 0xE3, 0x83, 0x9B, 0xE3, - 0x82, 0x99, 0x4, 0xCE, 0x99, 0xCC, 0x81, 0x3, 0x57, 0xCC, 0x88, 0x6, 0xCE, - 0xBF, 0xCC, 0x93, 0xCC, 0x80, 0x6, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x81, 0x3, - 0x64, 0xCC, 0xB1, 0x6, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82, 0x3, 0xE6, 0x91, - 0xB7, 0x5, 0x6F, 0xCC, 0x83, 0xCC, 0x84, 0x3, 0xE5, 0x9E, 0x8B, 0x3, 0xE9, - 0xB1, 0x80, 0x3, 0xE6, 0x8A, 0xB1, 0x3, 0xE6, 0x86, 0xAF, 0x6, 0xE3, 0x82, - 0xAB, 0xE3, 0x82, 0x99, 0x3, 0xE6, 0x9F, 0xBA, 0x3, 0xE5, 0x85, 0x80, 0x3, - 0xE5, 0x9C, 0x97, 0x5, 0x41, 0xCC, 0x86, 0xCC, 0x81, 0x6, 0xE0, 0xB3, 0x86, - 0xE0, 0xB3, 0x96, 0x3, 0xE6, 0x9B, 0xB8, 0x3, 0xE3, 0xB6, 0x96, 0x3, 0xE7, - 0x90, 0x86, 0x3, 0xE7, 0x94, 0x86, 0x4, 0xD7, 0xA4, 0xD6, 0xBF, 0x3, 0xE7, - 0x81, 0xB7, 0x3, 0xE5, 0xA3, 0x98, 0x3, 0xE6, 0xAD, 0xB2, 0x6, 0xCE, 0x9F, - 0xCC, 0x94, 0xCC, 0x80, 0x3, 0x68, 0xCC, 0xA7, 0x6, 0xCE, 0x91, 0xCC, 0x93, - 0xCC, 0x80, 0x3, 0x7A, 0xCC, 0x8C, 0x3, 0xE5, 0xA2, 0xA8, 0x6, 0xCE, 0xB9, - 0xCC, 0x93, 0xCD, 0x82, 0x3, 0xE3, 0xA1, 0xBC, 0x3, 0xE6, 0x88, 0x80, 0x3, - 0xE6, 0xB7, 0xAA, 0x6, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x99, 0x6, 0xCF, 0x89, - 0xCC, 0x81, 0xCD, 0x85, 0x6, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0x3, 0x4F, - 0xCC, 0x82, 0x3, 0xE7, 0xAB, 0xAE, 0x5, 0x4C, 0xCC, 0xA3, 0xCC, 0x84, 0x4, - 0xD7, 0xA9, 0xD7, 0x82, 0x3, 0xE7, 0x9E, 0x8B, 0x3, 0x48, 0xCC, 0xA7, 0x3, - 0xE7, 0xB4, 0x80, 0x3, 0x3E, 0xCC, 0xB8, 0x4, 0xCF, 0x85, 0xCC, 0x88, 0x5, - 0x4F, 0xCC, 0x82, 0xCC, 0x83, 0x4, 0xCE, 0x91, 0xCC, 0x94, 0x3, 0xE4, 0xB8, - 0x8D, 0x3, 0xE8, 0xA3, 0x97, 0x3, 0x68, 0xCC, 0x87, 0x6, 0xCF, 0x85, 0xCC, - 0x93, 0xCC, 0x80, 0x6, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC, 0x3, 0xE5, 0xA2, - 0xB3, 0x5, 0x41, 0xCC, 0x8A, 0xCC, 0x81, 0x3, 0xE6, 0xA8, 0x82, 0x3, 0xE8, - 0x87, 0x98, 0x6, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0xE6, 0xA6, 0xA3, - 0x8, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0x3, 0xE8, 0x97, 0xBA, - 0x5, 0x75, 0xCC, 0x83, 0xCC, 0x81, 0x5, 0x75, 0xCC, 0x88, 0xCC, 0x84, 0x3, - 0xE5, 0x90, 0x86, 0x4, 0xCC, 0x88, 0xCC, 0x81, 0x4, 0xF0, 0xA5, 0xBE, 0x86, - 0x3, 0xE7, 0x82, 0x99, 0x3, 0xE7, 0xB3, 0x96, 0x3, 0xE8, 0xB3, 0x93, 0x3, - 0xE7, 0xAA, 0x81, 0x3, 0x4C, 0xCC, 0xAD, 0x3, 0x72, 0xCC, 0x8C, 0x3, 0x4D, - 0xCC, 0x87, 0x3, 0x41, 0xCC, 0x83, 0x6, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x81, - 0x3, 0x6F, 0xCC, 0xA8, 0x4, 0xF0, 0xA3, 0x80, 0x8A, 0x3, 0x6E, 0xCC, 0xA7, - 0x8, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x4, 0xD0, 0x90, 0xCC, - 0x88, 0x3, 0xE5, 0x9B, 0xB9, 0x3, 0xE6, 0x86, 0xA4, 0x3, 0xE9, 0x80, 0xA3, - 0x3, 0xE6, 0x9D, 0x8E, 0x3, 0xE6, 0x85, 0x88, 0x3, 0x55, 0xCC, 0x8B, 0x3, - 0xE8, 0x81, 0x86, 0x3, 0xE5, 0xB6, 0xBA, 0x6, 0xE3, 0x82, 0xB3, 0xE3, 0x82, - 0x99, 0x3, 0xE8, 0x98, 0x86, 0x5, 0xE2, 0x89, 0xBC, 0xCC, 0xB8, 0x5, 0xE2, - 0x87, 0x92, 0xCC, 0xB8, 0x4, 0xF0, 0xA6, 0xAC, 0xBC, 0x3, 0xE5, 0x89, 0xB7, - 0x6, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0x3, 0x44, 0xCC, 0xA3, 0x8, 0xCE, - 0x91, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x3, 0xE8, 0x93, 0xB3, 0x3, 0xE8, - 0xBE, 0x9E, 0x3, 0x49, 0xCC, 0x84, 0x6, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x81, - 0x4, 0xD7, 0x94, 0xD6, 0xBC, 0x5, 0x55, 0xCC, 0x84, 0xCC, 0x88, 0x4, 0xD7, - 0xA3, 0xD6, 0xBC, 0x3, 0xE8, 0xAB, 0xBE, 0x3, 0xE7, 0xBE, 0x95, 0x3, 0x54, - 0xCC, 0x87, 0x3, 0xE9, 0x9F, 0x9B, 0x5, 0xE2, 0x8A, 0xB2, 0xCC, 0xB8, 0x3, - 0x72, 0xCC, 0xA7, 0x5, 0x45, 0xCC, 0x84, 0xCC, 0x80, 0x3, 0x4E, 0xCC, 0xB1, - 0x3, 0xE3, 0x80, 0x89, 0x3, 0xE6, 0x85, 0xA0, 0x6, 0xCE, 0xA9, 0xCC, 0x94, - 0xCD, 0x85, 0x5, 0xE1, 0xBF, 0xBE, 0xCD, 0x82, 0x5, 0x61, 0xCC, 0x86, 0xCC, - 0x80, 0x4, 0xD7, 0x95, 0xD6, 0xBC, 0x3, 0xE6, 0xB5, 0xA9, 0x3, 0xE8, 0x8F, - 0xB1, 0x4, 0xF0, 0xA5, 0x81, 0x84, 0x3, 0x59, 0xCC, 0x84, 0x3, 0xE8, 0x8E, - 0xAD, 0x8, 0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92, 0xB0, 0x6, 0xCE, 0xB9, - 0xCC, 0x88, 0xCD, 0x82, 0x3, 0x63, 0xCC, 0x82, 0x3, 0xE5, 0xAE, 0x85, 0x3, - 0xE5, 0xBB, 0x89, 0x3, 0xE9, 0xBE, 0x8D, 0x3, 0x73, 0xCC, 0x87, 0x5, 0xE2, - 0x8A, 0x86, 0xCC, 0xB8, 0x3, 0xE5, 0xA5, 0x84, 0x5, 0x6F, 0xCC, 0x82, 0xCC, - 0x81, 0xC, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, - 0xB0, 0x3, 0xE6, 0xB5, 0xB8, 0x3, 0xE8, 0x9A, 0xA9, 0x3, 0xE7, 0x92, 0x98, - 0x3, 0xE5, 0x97, 0x82, 0x6, 0xE0, 0xAD, 0x87, 0xE0, 0xAD, 0x97, 0x3, 0xE6, - 0x99, 0x89, 0x4, 0xCE, 0xB9, 0xCC, 0x86, 0x3, 0xE6, 0xAB, 0x9B, 0x6, 0xE0, - 0xAD, 0x87, 0xE0, 0xAD, 0x96, 0x3, 0xE7, 0xB3, 0xA7, 0x5, 0x69, 0xCC, 0x88, - 0xCC, 0x81, 0x3, 0x4C, 0xCC, 0xA3, 0x4, 0xD0, 0xB8, 0xCC, 0x80, 0x4, 0xD1, - 0x83, 0xCC, 0x86, 0x5, 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0x4, 0xF0, 0xA6, 0xBE, - 0xB1, 0x3, 0x67, 0xCC, 0x81, 0x3, 0xE6, 0x80, 0x9C, 0x3, 0xE9, 0xBC, 0xBB, - 0x3, 0xE8, 0x98, 0xBF, 0x4, 0xD0, 0x98, 0xCC, 0x86, 0x3, 0x49, 0xCC, 0xA3, - 0x6, 0xE0, 0xA8, 0xAB, 0xE0, 0xA8, 0xBC, 0x3, 0x41, 0xCC, 0x84, 0x6, 0xE3, - 0x82, 0xA6, 0xE3, 0x82, 0x99, 0x4, 0xCE, 0xB7, 0xCC, 0x80, 0x3, 0x55, 0xCC, - 0xA8, 0x6, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x81, 0x3, 0xE5, 0xA4, 0x86, 0x3, - 0xE3, 0xAB, 0xA4, 0x3, 0xE7, 0x99, 0x82, 0x3, 0xE5, 0x8D, 0x9A, 0x4, 0xCE, - 0xB9, 0xCC, 0x93, 0x3, 0xE5, 0x92, 0xA2, 0x5, 0x65, 0xCC, 0x82, 0xCC, 0x81, - 0x3, 0xE6, 0x85, 0xBA, 0x4, 0xF0, 0xA1, 0x9B, 0xAA, 0x4, 0xCE, 0x95, 0xCC, - 0x93, 0x4, 0xC6, 0xB7, 0xCC, 0x8C, 0x3, 0x4D, 0xCC, 0x81, 0x4, 0xD0, 0x90, - 0xCC, 0x86, 0x5, 0x75, 0xCC, 0x9B, 0xCC, 0x81, 0x4, 0xF0, 0xA4, 0xB2, 0x92, - 0x3, 0x55, 0xCC, 0x8C, 0x3, 0xE5, 0x8B, 0x9E, 0x3, 0xE9, 0xA3, 0xBC, 0x3, - 0xE3, 0xAD, 0x89, 0x3, 0xE7, 0xA4, 0xBC, 0x3, 0xE8, 0xAD, 0x98, 0x3, 0x45, - 0xCC, 0xA3, 0x4, 0xCE, 0xB9, 0xCC, 0x80, 0x3, 0xE6, 0xB3, 0x8C, 0x5, 0x55, - 0xCC, 0x9B, 0xCC, 0x89, 0x6, 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0x99, 0x6, 0xE1, - 0xAC, 0xBF, 0xE1, 0xAC, 0xB5, 0x4, 0xF0, 0xA2, 0x9B, 0x94, 0x3, 0xE6, 0x9E, - 0x85, 0x6, 0xE0, 0xA6, 0xA2, 0xE0, 0xA6, 0xBC, 0x5, 0xE2, 0x89, 0xBA, 0xCC, - 0xB8, 0x3, 0xE8, 0xAA, 0xBF, 0x3, 0xE8, 0xAB, 0x96, 0x3, 0xE7, 0xB3, 0xA3, - 0x5, 0x41, 0xCC, 0x82, 0xCC, 0x89, 0x6, 0xE0, 0xBE, 0x9C, 0xE0, 0xBE, 0xB7, - 0x5, 0x55, 0xCC, 0x83, 0xCC, 0x81, 0x6, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, - 0x3, 0xE6, 0xBC, 0x8F, 0x4, 0xF0, 0xA9, 0x90, 0x8A, 0x3, 0xE5, 0xBB, 0x93, - 0x3, 0xE4, 0xBE, 0xBB, 0x5, 0x63, 0xCC, 0xA7, 0xCC, 0x81, 0x3, 0xE7, 0x9C, - 0x81, 0x3, 0xE7, 0xA5, 0x90, 0x3, 0x52, 0xCC, 0xB1, 0x6, 0xE3, 0x83, 0x92, - 0xE3, 0x82, 0x99, 0x5, 0xE2, 0x89, 0xA4, 0xCC, 0xB8, 0x3, 0xE6, 0x9C, 0xA1, - 0x4, 0xCE, 0x91, 0xCC, 0x86, 0x3, 0x64, 0xCC, 0x87, 0x3, 0xE7, 0xA5, 0xBF, - 0x4, 0xCF, 0x85, 0xCC, 0x94, 0x4, 0xD7, 0xA4, 0xD6, 0xBC, 0x3, 0xE5, 0x86, - 0xB7, 0x3, 0xE4, 0x91, 0xAB, 0x8, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, - 0xA5, 0x4, 0xF0, 0xA5, 0x83, 0xB2, 0x3, 0x6D, 0xCC, 0x81, 0x6, 0xE3, 0x83, - 0x81, 0xE3, 0x82, 0x99, 0x3, 0x4F, 0xCC, 0xA8, 0x4, 0xF0, 0xA9, 0x96, 0xB6, - 0x3, 0x6C, 0xCC, 0xAD, 0x4, 0xD0, 0x95, 0xCC, 0x86, 0x3, 0xE7, 0x91, 0x9C, - 0x3, 0xE5, 0x8F, 0xA5, 0x3, 0xE7, 0x98, 0x90, 0x5, 0x55, 0xCC, 0x88, 0xCC, - 0x84, 0x3, 0xE6, 0xB8, 0xAF, 0x3, 0xE4, 0x80, 0x88, 0x3, 0x6F, 0xCC, 0x8B, - 0x6, 0xCF, 0x85, 0xCC, 0x94, 0xCD, 0x82, 0x3, 0x6D, 0xCC, 0xA3, 0x3, 0xE5, - 0x91, 0x82, 0x4, 0xCE, 0xA9, 0xCC, 0x94, 0x3, 0xE6, 0xA0, 0x97, 0x6, 0xCF, - 0x89, 0xCC, 0x94, 0xCC, 0x80, 0x3, 0x45, 0xCC, 0x87, 0x3, 0x54, 0xCC, 0xB1, - 0x6, 0xE3, 0x83, 0xB0, 0xE3, 0x82, 0x99, 0x4, 0xF0, 0xA6, 0xB0, 0xB6, 0x5, - 0xE1, 0xBF, 0xBE, 0xCC, 0x80, 0x3, 0xE6, 0xA2, 0x81, 0x4, 0xF0, 0xA1, 0xB7, - 0xA4, 0x5, 0xE2, 0x89, 0xBB, 0xCC, 0xB8, 0x3, 0x64, 0xCC, 0xA7, 0x4, 0xD0, - 0x9A, 0xCC, 0x81, 0x3, 0xE6, 0xAA, 0xA8, 0x3, 0x75, 0xCC, 0x81, 0x3, 0x45, - 0xCC, 0x8F, 0x6, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80, 0x3, 0x61, 0xCC, 0x81, - 0x6, 0xE1, 0xAC, 0xBC, 0xE1, 0xAC, 0xB5, 0x6, 0xE3, 0x83, 0x98, 0xE3, 0x82, - 0x9A, 0x3, 0xE8, 0x81, 0xA0, 0x3, 0xE2, 0x80, 0x82, 0x4, 0xD7, 0xA9, 0xD6, - 0xBC, 0x3, 0xE6, 0x9F, 0xB3, 0x3, 0xE5, 0xB7, 0xBD, 0x3, 0xE7, 0x98, 0x9F, - 0x5, 0xE2, 0x8A, 0xA2, 0xCC, 0xB8, 0x4, 0xD3, 0xA9, 0xCC, 0x88, 0x6, 0xCE, - 0xB1, 0xCC, 0x93, 0xCD, 0x85, 0x3, 0xE3, 0xB1, 0x8E, 0x3, 0x59, 0xCC, 0x83, - 0x3, 0xE5, 0x9F, 0x8E, 0x3, 0xE4, 0x97, 0x97, 0x3, 0xE5, 0x90, 0x8F, 0x3, - 0xE6, 0x87, 0xB2, 0x3, 0xE7, 0xAF, 0x86, 0x3, 0xE8, 0x8B, 0xA6, 0xC, 0xF0, - 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0x3, 0x4F, - 0xCC, 0x9B, 0x3, 0x69, 0xCC, 0x81, 0x4, 0xD7, 0x9B, 0xD6, 0xBC, 0x8, 0xCE, - 0xB7, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x3, 0xE4, 0x9B, 0x87, 0x3, 0xE4, - 0x8F, 0x99, 0x5, 0xE2, 0x89, 0xA5, 0xCC, 0xB8, 0x3, 0xE7, 0xB6, 0xBE, 0x3, - 0xE8, 0x8F, 0x89, 0x5, 0x6F, 0xCC, 0x9B, 0xCC, 0x81, 0x6, 0xCE, 0xB1, 0xCD, - 0x82, 0xCD, 0x85, 0x3, 0xE5, 0x8D, 0xBF, 0x5, 0x61, 0xCC, 0x82, 0xCC, 0x83, - 0x3, 0x4E, 0xCC, 0xA7, 0x3, 0xE9, 0x8B, 0x97, 0x8, 0xF0, 0x91, 0x84, 0xB2, - 0xF0, 0x91, 0x84, 0xA7, 0x3, 0x6B, 0xCC, 0x81, 0x6, 0xCF, 0x89, 0xCD, 0x82, - 0xCD, 0x85, 0x6, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80, 0x4, 0xD0, 0xAD, 0xCC, - 0x88, 0x3, 0x41, 0xCC, 0x8C, 0x6, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0x3, - 0xE8, 0x8F, 0xA7, 0x3, 0xE5, 0xBD, 0xA2, 0x3, 0x52, 0xCC, 0x8C, 0x5, 0x41, - 0xCC, 0x86, 0xCC, 0x83, 0x4, 0xD9, 0x8A, 0xD9, 0x94, 0x5, 0x4F, 0xCC, 0xA8, - 0xCC, 0x84, 0x6, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x80, 0x3, 0xE5, 0x85, 0xA8, - 0x4, 0xF0, 0xA3, 0xB2, 0xBC, 0x3, 0xE6, 0x9D, 0x93, 0x3, 0xE8, 0xB5, 0xB7, - 0x6, 0xE0, 0xA4, 0x96, 0xE0, 0xA4, 0xBC, 0x3, 0x49, 0xCC, 0x91, 0x4, 0xCE, - 0xB7, 0xCC, 0x93, 0x3, 0xE3, 0x93, 0x9F, 0x8, 0xF0, 0x91, 0x92, 0xB9, 0xF0, - 0x91, 0x92, 0xBD, 0x3, 0xE6, 0xB3, 0x8D, 0x8, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, - 0x80, 0xCD, 0x85, 0x8, 0xF0, 0x91, 0xA4, 0xB5, 0xF0, 0x91, 0xA4, 0xB0, 0x3, - 0x52, 0xCC, 0xA3, 0x3, 0x55, 0xCC, 0x91, 0x4, 0xF0, 0xA6, 0x89, 0x87, 0x6, - 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0x5, 0x75, 0xCC, 0x88, 0xCC, 0x8C, 0x3, - 0xE9, 0x99, 0xBC, 0x6, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x80, 0x4, 0xF0, 0xAA, - 0x84, 0x85, 0x3, 0x78, 0xCC, 0x87, 0x3, 0xE9, 0xA7, 0x82, 0x3, 0xE6, 0x88, - 0xB4, 0x3, 0xE6, 0x8D, 0xBB, 0x8, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCD, - 0x85, 0x4, 0xD0, 0x96, 0xCC, 0x86, 0x3, 0xE8, 0x8D, 0xA3, 0x6, 0xCE, 0x99, - 0xCC, 0x93, 0xCC, 0x80, 0x4, 0xF0, 0xA1, 0xB4, 0x8B, 0x6, 0xCE, 0xB1, 0xCC, - 0x94, 0xCC, 0x81, 0x4, 0xCE, 0xBF, 0xCC, 0x80, 0x6, 0xE0, 0xBE, 0x90, 0xE0, - 0xBE, 0xB5, 0x3, 0x48, 0xCC, 0x87, 0x6, 0xCF, 0x89, 0xCC, 0x80, 0xCD, 0x85, - 0x3, 0xE7, 0xBF, 0xBA, 0x3, 0xE6, 0xB9, 0xAE, 0x6, 0xE3, 0x81, 0xA6, 0xE3, - 0x82, 0x99, 0x3, 0xE4, 0xBB, 0x80, 0x8, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, - 0xCD, 0x85, 0x3, 0xE8, 0x81, 0xBE, 0x4, 0xD1, 0x83, 0xCC, 0x88, 0x3, 0x54, - 0xCC, 0x8C, 0x3, 0x74, 0xCC, 0xAD, 0x3, 0xE4, 0xBB, 0x8C, 0x5, 0xE1, 0xBE, - 0xBF, 0xCC, 0x81, 0x4, 0xCE, 0x97, 0xCD, 0x85, 0x5, 0x65, 0xCC, 0x82, 0xCC, - 0x89, 0x3, 0xE7, 0x94, 0xBB, 0x3, 0xE7, 0x93, 0x8A, 0x3, 0x48, 0xCC, 0xA3, - 0x3, 0xE5, 0xA1, 0x9E, 0x3, 0x4F, 0xCC, 0x87, 0x3, 0x68, 0xCC, 0xAE, 0x6, - 0xE0, 0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0x3, 0x4E, 0xCC, 0x80, 0x3, 0xE9, 0x9A, - 0xB7, 0x6, 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7, 0x6, 0xE3, 0x81, 0x97, 0xE3, - 0x82, 0x99, 0x3, 0x69, 0xCC, 0xB0, 0x3, 0xE8, 0x80, 0x81, 0x3, 0xE5, 0xBE, - 0x8B, 0x3, 0xE8, 0x93, 0xBC, 0x3, 0xE4, 0xA6, 0x95, 0x3, 0xE7, 0xBD, 0xB2, - 0x6, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99, 0x8, 0xCE, 0x91, 0xCC, 0x94, 0xCC, - 0x81, 0xCD, 0x85, 0x4, 0xF0, 0xA9, 0x85, 0x85, 0x3, 0xE7, 0x83, 0x99, 0xC, - 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB1, 0x3, - 0x66, 0xCC, 0x87, 0x4, 0xCE, 0x99, 0xCC, 0x86, 0x4, 0xCF, 0x81, 0xCC, 0x94, - 0x6, 0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x81, 0x2, 0xCC, 0x80, 0x3, 0x5A, 0xCC, - 0x8C, 0xC, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, - 0xAE, 0x6, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x95, 0x8, 0xCF, 0x89, 0xCC, 0x94, - 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE4, 0x83, 0xA3, 0x3, 0x56, 0xCC, 0xA3, 0x8, - 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0x5, 0x61, 0xCC, 0x86, 0xCC, - 0x83, 0x3, 0xE3, 0x94, 0x95, 0x4, 0xF0, 0xA4, 0x8E, 0xAB, 0x5, 0x4F, 0xCC, - 0x82, 0xCC, 0x81, 0x4, 0xF0, 0xA2, 0xA1, 0x84, 0x3, 0x75, 0xCC, 0x86, 0x3, - 0xE8, 0x98, 0x92, 0x3, 0xE5, 0x8A, 0x9B, 0x3, 0x44, 0xCC, 0xA7, 0x3, 0x65, - 0xCC, 0x86, 0x3, 0xE8, 0xA3, 0xB8, 0x3, 0x47, 0xCC, 0xA7, 0x3, 0xE8, 0x8F, - 0x9C, 0x3, 0xE3, 0xA4, 0x9C, 0x6, 0xE3, 0x83, 0xB1, 0xE3, 0x82, 0x99, 0x6, - 0xE0, 0xBE, 0xAB, 0xE0, 0xBE, 0xB7, 0x3, 0xE6, 0x9D, 0xBB, 0x3, 0xE6, 0xBF, - 0xAB, 0x5, 0x73, 0xCC, 0xA3, 0xCC, 0x87, 0x3, 0x6F, 0xCC, 0x84, 0x8, 0xCE, - 0x97, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0x3, 0x67, 0xCC, 0x84, 0x4, 0xD7, - 0x92, 0xD6, 0xBC, 0x3, 0x79, 0xCC, 0x82, 0x5, 0x4F, 0xCC, 0x82, 0xCC, 0x80, - 0x4, 0xD1, 0xB4, 0xCC, 0x8F, 0x5, 0x6F, 0xCC, 0x88, 0xCC, 0x84, 0x5, 0x55, - 0xCC, 0x88, 0xCC, 0x81, 0x3, 0x73, 0xCC, 0xA6, 0x3, 0x45, 0xCC, 0xA7, 0x6, - 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x99, 0x3, 0x50, 0xCC, 0x87, 0x4, 0xD0, 0xA3, - 0xCC, 0x8B, 0x3, 0xE7, 0xAF, 0x89, 0x6, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8F, - 0x3, 0xE7, 0x85, 0x85, 0x4, 0xD0, 0xB5, 0xCC, 0x80, 0x4, 0xCE, 0x99, 0xCC, - 0x93, 0x3, 0x65, 0xCC, 0xA7, 0x3, 0xE9, 0xA0, 0xA9, 0x3, 0xE7, 0xB2, 0xBE, - 0x3, 0x4B, 0xCC, 0xA7, 0x3, 0xE4, 0xBE, 0xBF, 0x3, 0xE9, 0xB1, 0x97, 0x6, - 0xE3, 0x81, 0xA4, 0xE3, 0x82, 0x99, 0x3, 0xE7, 0x99, 0xA9, 0x4, 0xF0, 0xA2, - 0xAC, 0x8C, 0x3, 0xE5, 0x8D, 0x89, 0x3, 0xE5, 0x8A, 0xB3, 0x3, 0x63, 0xCC, - 0x81, 0x5, 0xE2, 0x88, 0xBC, 0xCC, 0xB8, 0x6, 0xE0, 0xA4, 0xA1, 0xE0, 0xA4, - 0xBC, 0x3, 0xE4, 0xB8, 0xB2, 0x3, 0xE6, 0xAE, 0xAE, 0x4, 0xF0, 0xA5, 0xA5, - 0xBC, 0x4, 0xF0, 0xA3, 0x91, 0xAD, 0x6, 0xE0, 0xB2, 0xBF, 0xE0, 0xB3, 0x95, - 0x3, 0x47, 0xCC, 0x81, 0x6, 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x81, 0x3, 0xE4, - 0x8A, 0xA0, 0x3, 0xE6, 0xA1, 0x92, 0x6, 0xE3, 0x82, 0x9D, 0xE3, 0x82, 0x99, - 0x3, 0x65, 0xCC, 0x84, 0x3, 0x69, 0xCC, 0x91, 0x8, 0xCE, 0xA9, 0xCC, 0x94, - 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE6, 0x9A, 0x9C, 0x6, 0xE3, 0x81, 0xB8, 0xE3, - 0x82, 0x99, 0x6, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x82, 0x3, 0x49, 0xCC, 0x89, - 0x4, 0xD7, 0x95, 0xD6, 0xB9, 0x6, 0xE0, 0xAC, 0xA1, 0xE0, 0xAC, 0xBC, 0x3, - 0xE5, 0x86, 0x97, 0x3, 0x79, 0xCC, 0x81, 0x4, 0xD0, 0xA3, 0xCC, 0x86, 0x3, - 0x41, 0xCC, 0xA5, 0x3, 0x7A, 0xCC, 0x87, 0x3, 0xE6, 0xA8, 0x93, 0x3, 0x4E, - 0xCC, 0x87, 0x4, 0xCF, 0x89, 0xCC, 0x80, 0x4, 0xD7, 0x99, 0xD6, 0xB4, 0x3, - 0x6F, 0xCC, 0x83, 0x3, 0x3C, 0xCC, 0xB8, 0x3, 0xE8, 0x81, 0xAF, 0x4, 0xCE, - 0xB1, 0xCD, 0x82, 0x3, 0xE8, 0x9D, 0xAB, 0x3, 0xE7, 0x81, 0xB0, 0x3, 0xE3, - 0x9B, 0xAE, 0x3, 0xE7, 0x90, 0xA2, 0x3, 0xE7, 0xB9, 0x81, 0x3, 0xE6, 0xB2, - 0x88, 0x3, 0xE3, 0xBA, 0xAC, 0x4, 0xCF, 0x81, 0xCC, 0x93, 0x4, 0xF0, 0xA4, - 0x89, 0xA3, 0x3, 0xE5, 0x85, 0x94, 0x6, 0xE0, 0xA8, 0xB2, 0xE0, 0xA8, 0xBC, - 0x6, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x80, 0x4, 0xF0, 0xA5, 0xB2, 0x80, 0x6, - 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x81, 0x3, 0xE8, 0xAE, 0x80, 0x3, 0x4F, 0xCC, - 0x89, 0x6, 0xE0, 0xBE, 0xB3, 0xE0, 0xBE, 0x80, 0x6, 0xE0, 0xBE, 0xB2, 0xE0, - 0xBE, 0x80, 0x3, 0x61, 0xCC, 0x80, 0x3, 0x65, 0xCC, 0x91, 0x3, 0xE5, 0x85, - 0xB7, 0x3, 0xE5, 0x87, 0x8C, 0x3, 0xE5, 0x96, 0x87, 0x5, 0x4F, 0xCC, 0x83, - 0xCC, 0x88, 0x8, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x3, 0xE3, - 0xA9, 0xAC, 0x5, 0x61, 0xCC, 0x86, 0xCC, 0x89, 0x3, 0xE8, 0xB3, 0x88, 0x3, - 0x6B, 0xCC, 0xA3, 0x4, 0xCE, 0xB5, 0xCC, 0x93, 0x3, 0xE5, 0x83, 0x8F, 0x3, - 0x58, 0xCC, 0x87, 0x3, 0xE8, 0xBB, 0x8A, 0x8, 0xF0, 0x91, 0x96, 0xB8, 0xF0, - 0x91, 0x96, 0xAF, 0x6, 0xE3, 0x83, 0xBD, 0xE3, 0x82, 0x99, 0x3, 0xE6, 0xA5, - 0x82, 0x3, 0xE6, 0x8F, 0x84, 0x4, 0xD0, 0xBE, 0xCC, 0x88, 0x3, 0x44, 0xCC, - 0x8C, 0x3, 0x75, 0xCC, 0xA3, 0x4, 0xF0, 0xA0, 0xA8, 0xAC, 0x3, 0x77, 0xCC, - 0x82, 0x3, 0xE4, 0xBE, 0x8B, 0x3, 0xE5, 0x8F, 0xB1, 0x6, 0xE0, 0xB3, 0x86, - 0xE0, 0xB3, 0x82, 0x4, 0xCE, 0xB1, 0xCC, 0x80, 0x3, 0xE8, 0xA1, 0x8C, 0x3, - 0xE8, 0xB2, 0xAB, 0x3, 0x4E, 0xCC, 0x8C, 0x3, 0xE7, 0x8A, 0xAF, 0x3, 0xE5, - 0x8C, 0xBF, 0x4, 0xF0, 0xA0, 0xA0, 0x84, 0x5, 0x61, 0xCC, 0xA3, 0xCC, 0x82, - 0x3, 0xE5, 0xA1, 0x80, 0x3, 0xE4, 0x97, 0xB9, 0x4, 0xF0, 0xA7, 0x83, 0x92, - 0x5, 0xE2, 0x8A, 0xB5, 0xCC, 0xB8, 0x3, 0xE5, 0x92, 0x9E, 0x3, 0x65, 0xCC, - 0x83, 0x3, 0xE6, 0x9B, 0xB4, 0x3, 0xE7, 0x81, 0x8A, 0x3, 0xE4, 0x80, 0xB9, - 0x3, 0x6F, 0xCC, 0x82, 0x3, 0xE7, 0xB9, 0x85, 0x2, 0xC2, 0xB7, 0x3, 0x62, - 0xCC, 0xA3, 0x4, 0xCE, 0xA5, 0xCC, 0x86, 0x3, 0xE6, 0x8E, 0xA9, 0x4, 0xF0, - 0xA5, 0x9A, 0x9A, 0x3, 0xE9, 0x9C, 0xB2, 0x3, 0xE8, 0x8A, 0x91, 0x3, 0x55, - 0xCC, 0xAD, 0x3, 0xE5, 0xB8, 0xBD, 0x6, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x81, - 0x3, 0x69, 0xCC, 0x83, 0x3, 0x70, 0xCC, 0x87, 0x3, 0x65, 0xCC, 0x87, 0x3, - 0xE5, 0x88, 0x83, 0x3, 0xE7, 0x87, 0x8E, 0x3, 0x6F, 0xCC, 0x89, 0x4, 0xF0, - 0xA3, 0x8E, 0x93, 0x3, 0xE9, 0x89, 0xB6, 0x3, 0xE6, 0x9E, 0x97, 0x3, 0xE8, - 0x99, 0xA7, 0x3, 0xE8, 0xB7, 0xB0, 0x3, 0xE9, 0x82, 0x8F, 0x3, 0x77, 0xCC, - 0x87, 0x3, 0xE3, 0xB0, 0x98, 0x3, 0x55, 0xCC, 0x84, 0x3, 0xE9, 0xA3, 0xA2, - 0x3, 0xE6, 0xA0, 0x9F, 0x3, 0xE7, 0x9E, 0xA7, 0x6, 0xE3, 0x81, 0x95, 0xE3, - 0x82, 0x99, 0x6, 0xE0, 0xBE, 0xA6, 0xE0, 0xBE, 0xB7, 0x4, 0xCE, 0xB1, 0xCC, - 0x93, 0x3, 0x75, 0xCC, 0x8F, 0x3, 0xE8, 0xAB, 0x92, 0x5, 0xE2, 0x89, 0xB7, - 0xCC, 0xB8, 0x6, 0xCE, 0xB7, 0xCC, 0x81, 0xCD, 0x85, 0x5, 0xE2, 0x89, 0x83, - 0xCC, 0xB8, 0x3, 0xE6, 0x93, 0x84, 0x4, 0xCF, 0x85, 0xCC, 0x93, 0x3, 0xE7, - 0xB5, 0x9B, 0x3, 0x79, 0xCC, 0x83, 0x3, 0x69, 0xCC, 0x8F, 0x3, 0xE9, 0x9B, - 0xB7, 0x4, 0xF0, 0xA3, 0xBD, 0x9E, 0x5, 0x72, 0xCC, 0xA3, 0xCC, 0x84, 0xC, - 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0x3, - 0xE6, 0x88, 0x9B, 0x4, 0xD0, 0x93, 0xCC, 0x81, 0x6, 0xE0, 0xA6, 0xAF, 0xE0, - 0xA6, 0xBC, 0x8, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0x4, 0xF0, - 0xA6, 0x94, 0xA3, 0x3, 0xE9, 0x87, 0x8C, 0x8, 0xF0, 0x91, 0x92, 0xB9, 0xF0, - 0x91, 0x92, 0xBA, 0x4, 0xF0, 0xA7, 0xBC, 0xAF, 0x3, 0xE9, 0x9C, 0xA3, 0x3, - 0x6E, 0xCC, 0x80, 0x6, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x3, 0x61, 0xCC, - 0x84, 0x4, 0xF0, 0xA6, 0xBC, 0xAC, 0x3, 0xE7, 0xA9, 0x8A, -}; - -static const uint32_t _swift_stdlib_nfd_decomp_indices[2061] = { - 0x2F93B, 0x1400EE, 0x241E94, 0x36F874, 0x44FA9B, 0x56F87F, 0x641F44, 0x82F86A, - 0x92F9DA, 0xA01EA6, 0xB8307A, 0xD4F9DB, 0xE4FAA1, 0xF400DC, 0x104F96E, - 0x114F91A, 0x126F9AE, 0x1341EA5, 0x14C010B, 0x15C095D, 0x178FB41, 0x18CFA85, - 0x19D134B, 0x1C2F991, 0x1D2F828, 0x1E01F89, 0x1FC2ADC, 0x216F9F9, 0x22401B0, - 0x2340108, 0x24400C7, 0x256F8BC, 0x266F8AC, 0x2741F79, 0x288F951, 0x29800F2, - 0x2AAFA14, 0x2BCF9A8, 0x2CCFAD2, 0x2DCF9BE, 0x2ECF918, 0x2FC1EC2, 0x314FA1C, - 0x324FAB8, 0x3341F39, 0x3481ECD, 0x35AF9B8, 0x36AF841, 0x378095A, 0x396F933, - 0x3A400D6, 0x3B4038C, 0x3C8FB1F, 0x3DEF9F2, 0x3EC1F9C, 0x4101F9A, 0x436F82F, - 0x444FA8E, 0x456F90D, 0x46AF99C, 0x478F942, 0x488FA6C, 0x49EF8D4, 0x4AC012F, - 0x4BC011D, 0x4CC1E20, 0x4DC01D1, 0x4EC1EEA, 0x506FA05, 0x51401D4, 0x524FAD3, - 0x5341B12, 0x550FA58, 0x5601F1A, 0x57C0958, 0x598F995, 0x5AAF958, 0x5BAF879, - 0x5CAF918, 0x5D800D2, 0x5E8FA51, 0x5F8F9E8, 0x6080401, 0x61CFABB, 0x62C03AB, - 0x640F919, 0x652F9F1, 0x666F830, 0x6741E52, 0x68C00E5, 0x69C095F, 0x6B81F6F, - 0x6D6F865, 0x6E409DC, 0x7001E4C, 0x718020D, 0x72809CB, 0x744F9AD, 0x756F94B, - 0x764FAB7, 0x774FA15, 0x786FA1A, 0x794020E, 0x7A4FA2C, 0x7B6F8A5, 0x7C41E30, - 0x7D400EB, 0x7E4FA34, 0x7F401CF, 0x806F9AF, 0x816F8FA, 0x82401E3, 0x8380DDD, - 0x86000F1, 0x8701F0E, 0x88C00D9, 0x89EF848, 0x8AEF9B2, 0x8BCF98E, 0x8CEF8FC, - 0x8DC1E8E, 0x8EC1EDE, 0x906F945, 0x914F91B, 0x9241FC1, 0x9381F99, 0x956F9B6, - 0x966F895, 0x3B41FF9, 0x976F9CF, 0x984307D, 0x9A01E83, 0x9B01F4D, 0x9CC03CD, - 0x9E0FAA8, 0x9F0FA81, 0xA00F97F, 0xA101E04, 0xA22F9DB, 0xA301E32, 0xA40F92D, - 0xA52FA03, 0xA601F0F, 0xA7C3073, 0xA98F96A, 0xAA81E77, 0xAB804EE, 0xACEFA15, - 0xADCFABA, 0xAEC01FC, 0xB000103, 0xB12F80C, 0xB22F8C4, 0xB300230, 0xB48015A, - 0xB58F925, 0xB680144, 0xB781FA4, 0xB9C1F35, 0xBB81F81, 0xBD40104, 0xBE6F9E9, - 0xBF41EAF, 0xC0C1F1C, 0xC281F11, 0xC3CF999, 0xC4EFA17, 0xC5C1E3B, 0xC6C1EAC, - 0xC86F92E, 0xC94FA57, 0xCA6F8BB, 0xCB400CE, 0xCC401F0, 0xCD6F825, 0xCE41E15, - 0xCFC0DDE, 0xD1AF859, 0xD2CFAAA, 0xD3C0226, 0xD4CF9CC, 0xD5CF94B, 0xD6C06C2, - 0xD801FB2, 0xD9C0BCC, 0xDBAF812, 0xDCC03AF, 0xDE0FA79, 0xDF01F2A, 0xE0CF940, - 0xE1C0625, 0xE301E1E, 0xE42F91A, 0xE50F9F9, 0xE60FAA7, 0xE72F9FD, 0xE86F8CB, - 0xE96F9FC, 0xEA40161, 0xEB40227, 0xEC4FB38, 0xEDAF9F3, 0xEE81E65, 0xF02F9EE, - 0xF10F9E6, 0xF20FA35, 0xF30F91F, 0xF42F94F, 0xF501E95, 0xF600206, 0xF70305E, - 0xF8EF801, 0xF9CF977, 0xFAC09CC, 0xFCAF804, 0xFD81FAF, 0xFFC1E91, 0x100CFA3C, - 0x101C2278, 0x1036F856, 0x10441FDE, 0x105CF9B9, 0x106EF9F7, 0x1080F923, - 0x10900130, 0x10A01FF8, 0x10B4F989, 0x10C4F9D3, 0x10D4F9CD, 0x10E4FA83, - 0x10F4F93A, 0x11040386, 0x11180931, 0x1136F892, 0x1148FAB6, 0x1158015B, - 0x1168F975, 0x117AF8A1, 0x118AF8D9, 0x11981E90, 0x11A8FA5C, 0x11B8F9B3, - 0x11CAF810, 0x11D8F93D, 0x11E81EF2, 0x11FAF880, 0x1208FA66, 0x121AF8DD, - 0x122C2001, 0x123C0105, 0x124EF9C9, 0x125C03AE, 0x1270FA53, 0x1282F850, - 0x1290FAD9, 0x12A2F91E, 0x12B2F85D, 0x12C0F931, 0x12D2F8E2, 0x12E01F3E, - 0x12FCF976, 0x130C1F6C, 0x132AF971, 0x133AF8CE, 0x134AF8FF, 0x1358FA3E, - 0x1368F95B, 0x1378F9D5, 0x1388F939, 0x13981B0E, 0x13B42275, 0x13CC1FD1, - 0x13E0F900, 0x13F0F983, 0x14001F68, 0x141404D1, 0x1428FA6D, 0x1438FA98, - 0x14481EEE, 0x146000DD, 0x1472F975, 0x1484FAB2, 0x1496F9F8, 0x14A4F998, - 0x14B41FA0, 0x14D0012B, 0x14E2F8DB, 0x14F01FE7, 0x150C1EC6, 0x15241F61, - 0xF40F93B, 0x15380BCB, 0x1556F98A, 0x1568011A, 0x1578FA4C, 0x15880D4B, - 0x15A41E5C, 0x15BEF947, 0x15CC30D0, 0x15E8FAA0, 0x15F8FAAE, 0x16083054, - 0x16241E68, 0x163CF9A1, 0xE6F930, 0x164C2126, 0x165AF82A, 0x166803CE, - 0x167C00D5, 0x168C22AE, 0x16A4F9F5, 0x16B41E18, 0x16C4F971, 0x16D6FA10, - 0x16E81E4A, 0x16F8040D, 0x170CF9DD, 0x171C0200, 0x172C1EDA, 0x17440139, - 0x17541EDC, 0x176C30B8, 0x178800E3, 0x1798FA3D, 0x17A81F23, 0x17C41FC6, - 0x17DAFA16, 0x17E8F90A, 0x17FAF8F4, 0x18081EF5, 0x18181F82, 0x183CF9B6, - 0x184C30D9, 0x18681ED4, 0x18801EBC, 0x189000CD, 0x18A00F69, 0x18BCFA7B, - 0x18CCFA49, 0x18DCF962, 0x18EEF934, 0x18FCF9A6, 0x190CF9EA, 0x191C00C1, - 0x192C1F90, 0x194804E6, 0x195EF9E5, 0x19700477, 0x1984FAB5, 0x1996F8D3, - 0x19A430D4, 0x19C000CA, 0xC94F996, 0x19D2F888, 0x19E2F8AB, 0x19F00202, - 0x1A02F87E, 0x1A1004EA, 0x1A24FA67, 0x1A3401D0, 0x1A44FA41, 0x1A56F898, - 0x1A6AF926, 0x1A7EF9F0, 0x1A8EF9DE, 0x1A9C1FB9, 0x1AB01EF7, 0x1AC03094, - 0x1ADC1E8C, 0x1AEC1E19, 0x1AFC1E50, 0x1B141E9B, 0x1B281F98, 0x1B46F8E6, - 0x1B54013E, 0x1B6401DC, 0x1B7C1EE0, 0x1B96F8F5, 0x1BA6F95D, 0x1BBAF995, - 0x1BC81E88, 0x1BD910AB, 0x1BFEF8FE, 0x1C0C0A36, 0x1C281E93, 0x1C3AF89E, - 0x1C4AF87D, 0x1C5C01FF, 0x1C700211, 0x1C801E17, 0x1C980106, 0x1CAAF9AA, - 0x1CB81EE8, 0x1CD2F9E7, 0x1CE01FE9, 0x1CF6F9C8, 0x1D04F98C, 0x1D16F815, - 0x1D2404D3, 0x1D380385, 0x1D4C1E13, 0x1D5C1EC9, 0x1D6CFA73, 0x82F86B, - 0x1D7CFB48, 0x1D901FC2, 0x1DAEF9CB, 0x1DC00439, 0x1DD4F937, 0x1DE40163, - 0x1DF41EB9, 0x1E06F977, 0x1E181E1C, 0x1E300624, 0x1E46F976, 0x1E56F873, - 0x1E642262, 0x1E7EF882, 0x1E8CFB2F, 0x1EA0F974, 0x1EB01FB3, 0x1EC4021F, - 0x1ED4FA36, 0x1EE6F9F4, 0x1EF6F96C, 0x1F04FAC4, 0x1F14FA26, 0x1F2430D1, - 0x1F42F9E4, 0x1F52F8BE, 0x1F64F9D2, 0x1F7400EF, 0x1A24FA25, 0x1F84013D, - 0x1F941EBB, 0x1FA41F3F, 0x1FC2F822, 0x1FD01F62, 0x1FEC015F, 0x1FFEF9EA, - 0x200EF906, 0x2020095B, 0x203CF9AF, 0x204C01DF, 0x2064F9E3, 0x20740114, - 0x208430B0, 0x20A01EB2, 0x20B8F90D, 0x20CAF8C9, 0x20D8F954, 0x20E830BA, - 0x21041E75, 0x2116F8D2, 0x212401ED, 0x213C01D9, 0x21541F08, 0x21681FAA, - 0x218CF9A0, 0x219C0155, 0x21AEFA07, 0x21BC06C0, 0x21D01E0A, 0x21E01E74, - 0x21F01F3B, 0x220C1E97, 0x221C0160, 0x222EF9A8, 0x223C1F84, 0x22600134, - 0x2270F991, 0x22801FE2, 0x229CF9BC, 0x22AC0F57, 0x22C8FB39, 0x22DC1FBE, - 0x22E81B43, 0x2304FA5D, 0x23141EE6, 0x2324FAB3, 0x23341E58, 0x2344F921, - 0x2354F953, 0x23640162, 0x2376F9E2, 0x2386F9A6, 0x23981FFD, 0xD4F961, - 0x23A6F939, 0x23B8FA02, 0x23C80453, 0x23DCF981, 0x23ECF9EE, 0x23FCFA84, - 0x240CF91E, 0x241EFA19, 0x242EF974, 0x243EF986, 0x244C0DDA, 0x2468FB47, - 0x247C1F34, 0x249AF816, 0x24AEF935, 0x24C2F9A5, 0x24D4F92C, 0x24E4F946, - 0x24F4014C, 0x250400E9, 0x25141E7D, 0x25241FB0, 0x253AF9E0, 0x254C1EC1, - 0x25640341, 0x257000DA, 0x2580F9D4, 0x25901EA4, 0x25A81FFC, 0x25BC1E66, - 0x25D41EE1, 0x25EC012E, 0x25FCF985, 0x260EF93C, 0x26201E0D, 0x26300D4C, - 0x264C1E06, 0x265EF9C3, 0x266CFACA, 0x267EF948, 0x268C1F13, 0x26A8F99B, - 0x26B8FA45, 0x26C81F22, 0x26E6F9CA, 0x26F4F947, 0x2704FA46, 0x2714F915, - 0x2724FA6A, 0x27341EF0, 0x274EF842, 0x275EF9D1, 0x276C020F, 0x277C1F73, - 0x27901EC7, 0x27A81FFB, 0x27BC1FED, 0x27D0FA4D, 0x27E0F9F3, 0x27F0F92A, - 0x19E0FA89, 0x2802F96F, 0x28100F81, 0x282EF981, 0x283C011B, 0x284EF950, - 0x285CF9BD, 0x286CF98D, 0x287EF9D2, 0x288C2274, 0x28A4FA05, 0x28B41F9F, - 0x28D81FBA, 0x28EEF88E, 0x28FC1FCD, 0x2916F8EC, 0x292AF897, 0x293EF993, - 0x294C1E7B, 0x2966F854, 0x2976F863, 0x298422AF, 0x299CFB3A, 0x29B00176, - 0x29C2F87A, 0x29D01EBA, 0x29E0FAC3, 0x29F2F9D6, 0x2A000169, 0x2A100143, - 0x2A200F52, 0x2A3C1E63, 0x2A4CF9CA, 0x2A5CFACB, 0x2A6C1E34, 0x2A7EF9E1, - 0x2A901FBC, 0x2AA4FA88, 0x2AB4FAA6, 0x2AC422E1, 0x2ADEF9EB, 0x2AECF943, - 0x2AFC00E4, 0x2B0CF979, 0x2B1CF9B2, 0x2B2CF908, 0x2B3C0156, 0x2B4C1FAE, - 0x2B70014E, 0x2B80FA91, 0x2A5EF9FE, 0x2B9115BB, 0x2BB4015D, 0x2BC4F993, - 0x2BD4FA30, 0x2BE41E64, 0x2BFEF8EA, 0x2C0C015E, 0x2C1C0218, 0x2C2CF93F, - 0x2C3C1FE0, 0x2C5004F0, 0x2C66F985, 0x2C741F54, 0x2C92F907, 0x2CA0F9FF, - 0x2CB2F83F, 0x2CC01E6C, 0x2CD2F99F, 0x2CE2F857, 0x2CF0F9F7, 0x2D001FEB, - 0x2D141E2A, 0x2D241E03, 0x2D341EE4, 0x2D441E67, 0x2D5EF836, 0x2D6C1F29, - 0x7E6F827, 0x2D800120, 0x2D92F88D, 0x2DA0F978, 0x2DB2F8D6, 0x2DC2F9AC, - 0x2DD2F9D0, 0x2DE2F9A2, 0x2DF01F60, 0x2E06F86E, 0x2E143071, 0x2E30F97C, - 0x2E4030FA, 0x2E5CF988, 0x2E6C1E5F, 0x2E7EF83D, 0x27403CC, 0x2E8CF9A7, - 0x2E9CF96B, 0x2EAC1F21, 0x2EC01E35, 0x2ED2F966, 0x2EE0011F, 0x2EF000FC, - 0x2F00F97E, 0x2F12F90F, 0x2F20F9B1, 0x2F32F987, 0x2F46F93E, 0x2F56F871, - 0x2F681EA2, 0x2F7AF9CC, 0x2F8CF9CF, 0x2F9EF915, 0x2FACF9D1, 0x2FBC1F95, - 0x2FE004E3, 0x2FF4F911, 0x3006F9B9, 0x3014F984, 0x3026F960, 0x3036F8CF, - 0x304400F3, 0x3056FA09, 0x30680233, 0x3078010C, 0x308804F9, 0x309CF9FE, - 0x30AEF988, 0x30C01E08, 0x30D81FA6, 0x30FCF950, 0x310CFB36, 0x31200124, - 0x31300F43, 0x314C1E25, 0x315C00CB, 0x316EF9E6, 0x317C1F5D, 0x319AF9C7, - 0x31A81E7F, 0x2AB4FA17, 0x31BAF9B4, 0x31C8FB4D, 0x31DC1EEF, 0x31F41E92, - 0x3206F936, 0x3216F8BA, 0x3224F909, 0x3234F929, 0x3246F849, 0x325401FE, - 0x32681F19, 0x327C1F07, 0x100EF878, 0x3299109A, 0x32BCF924, 0x32CC0102, - 0x32DEF809, 0x32EC1ED7, 0x3306F81C, 0x3318011C, 0x33280B94, 0x33441EEB, - 0x335C01D8, 0x33741B0A, 0x339000C4, 0x33A0FACF, 0x33B40118, 0x33C6F9BE, - 0x33D6F8B9, 0x33E6F9FA, 0x33F6F870, 0x3406F847, 0x3416F86D, 0x34241FC8, - 0x34381F86, 0x345EF8BD, 0x346EF85E, 0x347D134C, 0x34A00165, 0x34B2F9A7, - 0x34C000E7, 0x2A5EF9FF, 0x34D2F98C, 0x34E2F81D, 0x34F0F964, 0x3500017A, - 0x3512F94D, 0x3526F87C, 0x3534F99E, 0x3544F9DF, 0x35541E54, 0x3564F966, - 0x3576F875, 0x35841E4D, 0x359C1B0C, 0x35B804DA, 0x35CEF9EC, 0x35DCF9BB, - 0x1136F891, 0x35EEF964, 0x35FC016F, 0x360EF929, 0x361C1B06, 0x36380135, - 0x3648FA8F, 0x36581F14, 0x3674012C, 0x368403D3, 0x3699D160, 0x9CC1F7B, - 0x125C1F75, 0x36CC0210, 0x36DC04E4, 0x36F0F9CB, 0x3702F92C, 0x37101EDD, - 0x3729D15E, 0x374EF844, 0x375C0343, 0x37681F56, 0x3784F9C7, 0x37940CCB, - 0x37BEF860, 0x37D00171, 0x37E0010D, 0x37F0FA60, 0x3802F9A0, 0x3812F88B, - 0xC94FAB0, 0x382001A1, 0x3830F9AA, 0x3840FA71, 0x3850FA2E, 0x3860220C, - 0x38780125, 0x284CFAAB, 0x3888FA0A, 0x38981F5F, 0x38B41026, 0x38D0F9D0, - 0x38E0FA7F, 0x38F0017B, 0x3902F920, 0x39101F97, 0x39341EB6, 0x394EF8C2, - 0x395C01E8, 0x396C0BCA, 0x398AF814, 0x399804E2, 0x39AC1F6E, 0x39C80F73, - 0x39E4FA48, 0x39F41F0D, 0x3A101ED5, 0x3A2AF9D3, 0x3A3C1E2E, 0x3A540B4B, - 0x3A701F53, 0x3A8C0388, 0x3AA0FA09, 0x3AB0F9DC, 0x3AC2F944, 0x3AD4FB3C, - 0x3AEAF85B, 0x3AF82260, 0x3B0806D3, 0x3B1C1F8A, 0x3B401FD6, 0x3B56FA0D, - 0x3B6430AE, 0x3B8001AF, 0x3B901EE3, 0x3BAAF9B3, 0x3BB9D1BC, 0x3BDC0622, - 0x3BF00F4D, 0x3C0C1E55, 0x3C1CFA07, 0x3C2EF803, 0x3C400214, 0x3C50F9C6, - 0x3C60F95E, 0x3C701EA7, 0x3C8AF85A, 0x3C981E86, 0x3CA8305C, 0x3CC404F5, - 0x3CD8FA1E, 0x3CE800F9, 0x3CF81E47, 0x3D0AF818, 0x3D1801E6, 0x3D2AF90E, - 0x3D381F01, 0x3D4C04F8, 0x3D60012D, 0x3D7022AD, 0x3D881E42, 0x3D981E99, - 0x3DA81E4F, 0x3DC01E26, 0x3DD004ED, 0x3DE6F9C5, 0x3DFAF88C, 0x3E0822EC, - 0x3E201E62, 0x3E301EC5, 0x3E4AF851, 0x3E58FA19, 0x3E68212A, 0x3E703052, - 0x3E8C1F26, 0x3EA81E60, 0x3EBAF912, 0x3EC8F9F1, 0x3ED80C48, 0x3EF4FA90, - 0x3F041FAD, 0x3F2AFA0F, 0x3F3AF862, 0x3F48FA32, 0x3F5800D1, 0x26BAF901, - 0x3F6801E1, 0x3F80F904, 0x3F90F932, 0x3FA2F9A1, 0x3FB003AA, 0x3FC5D161, - 0x3FF81F6A, 0x4016FA1B, 0x4024FAB4, 0x40341E81, 0x40441F2E, 0x4062F972, - 0x4074FB30, 0x40881EBE, 0x40A0F956, 0x40B0010F, 0x40C01F48, 0x40D4F9E5, - 0x40E4F9E2, 0x40F401E0, 0x410C04DE, 0x4120305A, 0x413C01FB, 0x4154F9C5, - 0x4164FA86, 0x41741FEA, 0x418AF9DD, 0x419CFB4A, 0x41B01F1B, 0x41CEF905, - 0x41DEF9AB, 0x41F01B40, 0x420EF8A0, 0x421CFA2D, 0x422EF837, 0x423CFA75, - 0x424EF83E, 0x425C1ECB, 0x426C1ED8, 0x4286F864, 0x42941E12, 0x42A6F8C3, - 0x42B6F8B4, 0x42C41EE2, 0x42DC00C8, 0x42EEF927, 0x4300037E, 0x43081E70, - 0x4318226D, 0x43301F67, 0x3832F86F, 0x434CF98F, 0x435C021B, 0x436EFA0A, - 0x437EF91B, 0x4390FA4B, 0x43A01F43, 0x43BC0457, 0x43D0F9CE, 0x43E030D7, - 0x3236F8D8, 0x43FC1E02, 0x440C01DB, 0x4426F866, 0x4436F952, 0x444AF9E3, - 0x445AF84F, 0x275CFAC0, 0x4468FA1B, 0x447AF92B, 0x44881F71, 0x449EF829, - 0x44ACF9D7, 0x44BCF9AE, 0x44CC3077, 0x44E8F91C, 0x44F80A5B, 0x45141FB4, - 0x4530011E, 0x454004F3, 0x45540212, 0x4566FA18, 0x4574219B, 0x458C1F72, - 0x45A0F917, 0x45B2F808, 0x45C2FA1D, 0x45D41FCA, 0x45E803B0, 0x46041F02, - 0x4622F99D, 0x463001EF, 0x464404EF, 0x46581F6B, 0x46741EF3, 0x4686F8F6, - 0x469400FB, 0x46A43050, 0x46C02204, 0x46D8021A, 0x46EAF853, 0x46FAF869, - 0x47081FEF, 0x47103070, 0x472CFB2D, 0x474AF8F9, 0x475CF9ED, 0x476CFA82, - 0x477CF98B, 0x478C0201, 0x479EF8C0, 0x47AEF845, 0x47BC1FF6, 0x1ED4FA78, - 0x47D2F984, 0x47E001DE, 0x15BEF946, 0x47FAF900, 0x48081F66, 0x4826F8B2, - 0x48341F28, 0x4848F994, 0x485AF8F0, 0x486CF969, 0x487EF990, 0x488EF924, - 0x489C0451, 0x48B2F97F, 0x48C01E37, 0x48D0FA33, 0x48E01E2C, 0x48F01E98, - 0x49000128, 0x49100112, 0x49201EA1, 0x49301E80, 0x4942F999, 0x49502226, - 0x49680FA2, 0x498400DB, 0x49941EB7, 0x49AC2289, 0x49C4F986, 0x49D6F820, - 0x49E4022F, 0x49F41FE1, 0x4A08F9EC, 0x4A18FAD1, 0x4A2CFB31, 0x4A4004DD, - 0x4A541F59, 0x4A6822EB, 0x4A801E51, 0x4A9800F6, 0x4AA8F90C, 0x4AB8FA2A, - 0x4AC804D7, 0x4ADEF84B, 0x4AEC1EA9, 0x4B04FAC1, 0x4B14F90F, 0x4B241EB0, - 0x4B3C2329, 0x4B4C21CD, 0x4B66F890, 0x4B741E53, 0x4B8C0231, 0x4BA40173, - 0x446AF956, 0x267CFAA9, 0x4BB40178, 0x4BC41F64, 0x4BE000C5, 0x4BF01FC7, - 0x4C0C1F3C, 0x4C28F9F8, 0x4C38F982, 0x3404FA7A, 0x4C4AFA0C, 0x4C58F92B, - 0x4C6AF90A, 0x4C781E1D, 0x4C92F925, 0x4CA2F922, 0x4CB2F813, 0x4CC01E8F, - 0x4CD0022A, 0x4CE800CF, 0x4CFAFA04, 0x4D081F9E, 0x4D2C1F41, 0x4D40FAC7, - 0x4D501F40, 0x4D641F88, 0x4D82F96E, 0x4D92F9C0, 0x4DA2F80D, 0x4DB6F84E, - 0x4DC4F948, 0x4DD4013A, 0x4DE4020C, 0x4DF40400, 0x4E08FB2E, 0x4E1C1E3A, - 0x4E2CFB4C, 0x4E401F93, 0x4E64095E, 0x4E8030B2, 0x31B8F936, 0x4E9EF95B, - 0x4EAEF8B7, 0x4EBEF9BA, 0x45E81FE3, 0x4ECC1F9D, 0x4EF0FA38, 0x4F02F9C4, - 0x4F101E46, 0x4F20FABC, 0x4F300213, 0x4B04FA65, 0x4F40FB2A, 0x4F541E6D, - 0x4F64FAD5, 0x4F7800EC, 0x4F883069, 0x4FA400C0, 0x4FB4FA63, 0x4FC6F839, - 0x4FD4F987, 0x4FE41E27, 0x4FF41E8D, 0x500430C9, 0x5022F881, 0x50301FD2, - 0x504EF876, 0x505C1F49, 0x1D381FEE, 0x50701F2C, 0x508C0123, 0x509C04DF, - 0x50B2F8F1, 0x50C0010A, 0x50D0013B, 0x50E030C5, 0x50FEF8A9, 0x510C1EC0, - 0x5124FB46, 0x513AF877, 0x51480F93, 0x5166F89D, 0x5176F838, 0x51881E45, - 0x519801FD, 0x51AC0B5D, 0x51C8045C, 0x51DEF90C, 0x51EC219A, 0x52041FC3, - 0x52180205, 0x522821AE, 0x5242F872, 0x52500168, 0x526000FF, 0x5271D1C0, - 0x52A6F968, 0x52B6F9ED, 0x52CAF887, 0x52D8016B, 0x52E8FA50, 0x52F8013C, - 0x53081E39, 0x532000C9, 0x53301E6B, 0x5340FA99, 0x53501FCB, 0x536401D2, - 0x5374F933, 0x53841E89, 0x5396F8BF, 0x53A5112E, 0x53C8304E, 0x53E41E7C, - 0x53F4016C, 0x540422E2, 0x541C1F8E, 0x54401F91, 0x545EF955, 0x54701EF4, - 0x548001E7, 0x54900119, 0x54A0FA3B, 0x54B2F994, 0x54C030C7, 0x54DEF8AF, - 0x54EC1FA8, 0x2CD0FA5F, 0x550AFA0E, 0x55181F96, 0x553C00C2, 0x554CFA70, - 0x555EF961, 0x55703074, 0x558CF9C3, 0x559CFA37, 0x2B2CFACE, 0x55AC1F7A, - 0x55C0FB40, 0x55D4FA4E, 0x55E400D3, 0x55F6FA08, 0x5604FA80, 0x5614FA01, - 0x5626F913, 0x56341B08, 0x5650F960, 0x5660FA94, 0x5672F858, 0x568001CE, - 0x569000CC, 0x56A01E73, 0x56B0F944, 0x56C2F97E, 0x56D41FD9, 0x56EAF889, - 0x56FEF921, 0x570CF963, 0x571C30F7, 0x5738F91D, 0x574AF81A, 0x575AF807, - 0x5768F94F, 0x57780217, 0x578AF8EF, 0x5798FA56, 0x57A8F9B7, 0x5798FAAD, - 0x57B8FA7C, 0x57C8F9B4, 0x57D82209, 0x57F01ED9, 0x5808FB2C, 0x1986F9BB, - 0x58241FE6, 0x583AFA13, 0x584C1EC4, 0x58641F6D, 0x58801EED, 0x5898FAAC, - 0x58A81FB1, 0xADCFA22, 0x58BCFA42, 0x58CCF927, 0x58DDD164, 0x59101FFA, - 0x5924F9BA, 0x56FCFA9E, 0x59341F45, 0x5952F911, 0x59641FA1, 0x598000E8, - 0x59901FA5, 0x59B42247, 0x59CCFAD7, 0x59E01E49, 0x59F0F9F6, 0x5A002249, - 0x5A181E07, 0x5A282284, 0xF22F82D, 0x5A401F37, 0x5A5CFA52, 0x5A6C1E85, - 0x5A7C1E4B, 0x5A8CFAC2, 0x5A9C1E0E, 0x5AAEF821, 0x5ABEF943, 0x5AD2F931, - 0x5AE2F957, 0x5AF2F97B, 0x5B06F959, 0x5B141EAA, 0x5B2CFA9A, 0x5B3C022C, - 0x5B56F896, 0x5B640F75, 0x5B800137, 0x5B901E59, 0x5BA0FAD6, 0x5BB43060, - 0x5BD004DC, 0x5BE4016E, 0x5BF6F982, 0x5C041E01, 0x5C1403D4, 0x5C28F9E0, - 0x5C381E6F, 0x5C481F24, 0x5C66F885, 0x5C741FAC, 0x5C98F9A3, 0x5CA8014F, - 0x5CBAF80A, 0x966F894, 0x5CCAF9CD, 0x5CD8F9FA, 0x5CE81EDF, 0x5D02F8F7, - 0x5D14F992, 0x5D241EA0, 0x5D341E1B, 0x5D44FA1A, 0xDCC1F77, 0x5D55109C, - 0x5D781EF6, 0x5D88F99D, 0x5D981F83, 0x5DBCF9D9, 0x5DCC04F4, 0x5DE01ECC, - 0x5DF004E5, 0x5E0401E9, 0x20BAF8B1, 0x2D00038E, 0x5E141E16, 0x5E2EF94C, - 0x5E3CFA06, 0x5E4EF88F, 0x5E60F959, 0x5E701FD3, 0x5E8C04DB, 0x5EA2F983, - 0x5EB0F920, 0x48D2F826, 0x5EC01EE7, 0x5ED01FCF, 0x5EEAF8A8, 0x5EFAF923, - 0x5F0C00E2, 0x5F1EF9C1, 0x5F2EF86C, 0x5F400179, 0x5F5021CE, 0x5F6801E2, - 0x1EA2F998, 0x5F7C30C0, 0x5F9830B6, 0x5FB6F94E, 0x5FC400EA, 0x5FD4304C, - 0x5FF01B3B, 0x600EFA11, 0x601C04C2, 0x2B80FA12, 0x6032F800, 0x60401E5B, - 0x60502285, 0x6068F99F, 0x6078FAA4, 0x60881EA3, 0x60981EF1, 0x60B2F868, - 0x60C2F802, 0x5CB8FA31, 0x60D00A59, 0x60EC021E, 0x60FC0174, 0x610C1E41, - 0x39E4FA9C, 0x611EF89C, 0x612EF96D, 0x613CFAD8, 0x614C1FEC, 0x6160FA74, - 0x2A4CFA97, 0x6172F941, 0x61841E1A, 0x61941FF3, 0x61A81F5B, 0x61C4F973, - 0x61D6F843, 0x61E6F928, 0x61F40208, 0x6206F8D0, 0x62141E72, 0x6226F9D5, - 0x62341FDA, 0x624AF8C5, 0x625AF98B, 0x626AF8E4, 0x627AF9BC, 0x62880407, - 0x629C1F31, 0x62B03076, 0x62CC22E3, 0x62E6F85F, 0x2724FACC, 0x62F6F8B6, - 0x6304F952, 0x6314FA95, 0x63240154, 0x5342F90B, 0x6334FB3E, 0x6348F99C, - 0x277C03AD, 0x63580623, 0x636CFA0D, 0x637C0203, 0x638CFAB1, 0x639EF980, - 0x63B00121, 0x63C01E96, 0x63D0F9E7, 0x63E2F89A, 0x63F02224, 0x64080A5A, - 0x64241E82, 0x6434F94D, 0x64440150, 0x6456F883, 0x6464FA6B, 0x647403CA, - 0x6488015C, 0x649AF89B, 0x64A80148, 0x1A46F8C8, 0x64B81F12, 0x64D4F9B8, - 0x15E8FA16, 0x64E4FB33, 0x64F80374, 0x6506F89F, 0x651430DC, 0x6530038A, - 0x65441E84, 0x65541F42, 0x9E2F940, 0x1BA6F95E, 0x65701F1D, 0x658C1E0F, - 0x659C1F27, 0x65BAF8C6, 0x65C8022D, 0x65E2F855, 0x65F2FA0B, 0x6602F8B5, - 0x6612F8AE, 0x662030AC, 0x663EF8DF, 0x664CFA0C, 0x665EF84D, 0x666C1EAE, - 0x66840CC8, 0x66A2F8CC, 0x66B2F916, 0x66C0F9E4, 0x66D0FAA2, 0x66E0FB4E, - 0x66F6F919, 0x6704F94A, 0x6716F8F3, 0x67241F4B, 0x52EAF953, 0x67401E29, - 0x67501F0A, 0x676C017E, 0x677CFA3A, 0x678C1F36, 0x67AAF88A, 0x18DEF938, - 0x67B8F990, 0x67C8F9D6, 0x67D8307C, 0x67F41FF4, 0x68101F25, 0x4FB4FABF, - 0x682C00D4, 0x683EF95F, 0x684C1E38, 0x6864FB2B, 0x687AF94A, 0x68881E28, - 0x689AF96A, 0x68A8226F, 0x68B803CB, 0x68CC1ED6, 0x68E41F09, 0x68F8F967, - 0x690AF9C6, 0x69181E23, 0x69281F52, 0x69440929, 0x6960FA7D, 0x697001FA, - 0x6988F914, 0x6998F926, 0x2DD0FABE, 0x69A81F4C, 0x69C6F8E9, 0x69D41FA7, - 0x69F8F9F0, 0x6A081E79, 0x6A2001D6, 0x324FA61, 0x6A3AF83B, 0x6A480344, - 0x6A5EF96B, 0x6A70F9FB, 0x6A80FA03, 0x6A90FA64, 0x6AA0FA55, 0x6AB01E3C, - 0x6AC00159, 0x5B04FA54, 0x6AD01E40, 0x6AE000C3, 0x6AF01F2D, 0x6B0C01EB, - 0x6B1EF8CA, 0x6B300146, 0x6B401F85, 0x46F914, 0x6B6404D2, 0x6B78F9A9, - 0x6B8AF8AD, 0x3702F92D, 0x6B98F99A, 0x27A8038F, 0x6BA8F9E1, 0x6BBAF8A6, - 0x1280FA00, 0x6BC80170, 0x6BD8F9B0, 0x5E700390, 0x6BE8F9AB, 0x3034FA43, - 0x6BF830B4, 0x6C14F935, 0x6C2422E0, 0x6C3C21CF, 0x6C56F997, 0x6C6AF823, - 0x6C781F06, 0x6C941E0C, 0x6CA41F8C, 0x6CCAF9A9, 0x6CDAF98D, 0x6CE8012A, - 0x6CF81F15, 0x6D14FB34, 0x6D281E7A, 0x6D40FB43, 0x6D54FABD, 0x6D66F978, - 0x6D741E6A, 0x6D84FAC9, 0x6D9422EA, 0x6DAC0157, 0x6DBC1E14, 0x6DD41E48, - 0x6DE4232A, 0x6DF4FA8A, 0x6E041FA9, 0x6E201FDF, 0x6E381EB1, 0x6E50FB35, - 0x6E66F903, 0x6E74F958, 0x6E86F93D, 0x6E980232, 0x6EAAF99B, 0x6EB914BC, - 0x6EDC1FD7, 0x6EF80109, 0x6F08FA04, 0x6F18F9A2, 0x6F28F9C4, 0x6F381E61, - 0x6F482288, 0x448803AC, 0x6F60FA7E, 0x6F701ED1, 0x6F89D162, 0x6FBEF904, - 0x6988F9BF, 0x6FCEF9B7, 0x6FDCF9EF, 0x6FEEF84A, 0x6FFC0B4C, 0x701AF8CD, - 0x70281FD0, 0x703EF8ED, 0x704C0B48, 0x7068F97B, 0x70781E2F, 0x70901E36, - 0x70A0045D, 0x70B4045E, 0x70C81ED3, 0x70E2F9B0, 0x70F401F5, 0x7104F9AC, - 0x7116FA1C, 0x7124F910, 0x71340419, 0x71481ECA, 0x71580A5E, 0x71740100, - 0x718430F4, 0x71A01F74, 0x71B40172, 0x71C41F55, 0x71E2F85C, 0x71F2F8D1, - 0x7200F9C1, 0x7212F82E, 0x72201F30, 0x7236F840, 0x72441EBF, 0x725EF8AA, - 0x726EF861, 0x72801F18, 0x729401EE, 0x72A81E3E, 0x72B804D0, 0x72CC1EE9, - 0x72E6F937, 0x72F801D3, 0x1D0FA77, 0x7308F92F, 0x7318FA2B, 0x732AF8DE, - 0x6988F95C, 0x7338FA18, 0x7348F9FC, 0x73581EB8, 0x73681F76, 0x737CF968, - 0x738C1EEC, 0x73A430BE, 0x73C01B41, 0x73DEF8A4, 0x73F2F8E0, 0x19E0FA3F, - 0x740009DD, 0x741C2280, 0x7434FAB9, 0x7444F941, 0x7456F969, 0x74641EA8, - 0x747C0F9D, 0x74981E78, 0x74B030BC, 0x74CCF94E, 0x74DEF9FB, 0x74F0FA0B, - 0x7502F806, 0x75101E09, 0x7528F96D, 0x7538FA4F, 0x75481E5E, 0x755830D3, - 0x75742270, 0x758EF8DA, 0x759C1FB8, 0x75B01E0B, 0x75C0F93C, 0x75D01F51, - 0x75E4FB44, 0x75F8F92E, 0x760AF98E, 0x7619D1BB, 0x763EF942, 0x76501E3F, - 0x766030C2, 0x767C01EA, 0x768EFA01, 0x76A01E3D, 0x76B004D6, 0x76C6F92F, - 0x76D4F906, 0x76E6F93A, 0x76F401D5, 0x770EF908, 0x771EF93F, 0x772C0151, - 0x773C1F57, 0x77581E43, 0x7768F980, 0x77781F69, 0x778CF9DA, 0x779C1F63, - 0x77B80116, 0x1486F97A, 0x77C81E6E, 0x77D830F8, 0x77F6F9A4, 0x78081FDD, - 0x7820F97A, 0x5B2CFA47, 0x7832F87B, 0x78442281, 0x785C1E11, 0x786C040C, - 0x7882F8EB, 0x789000FA, 0x2304FA5E, 0x78A00204, 0x78B01F33, 0x78CC00E1, - 0x78DC1B3D, 0x78F830DA, 0x7916F97D, 0x79242000, 0x7934FB49, 0x7948F9C9, - 0x5EE8FA87, 0x795AF884, 0x7968FAA5, 0x797822AC, 0x799004EB, 0x79A41F80, - 0x79C2F8F2, 0x79D01EF8, 0x79E2F852, 0x79F2F9BF, 0x7A00F9DE, 0x7A12F8B0, - 0x7A22F962, 0x7A32F996, 0x7A41D1BF, 0x7A7401A0, 0x7A8400ED, 0x7A94FB3B, - 0x7AA81F94, 0x7ACEF9CE, 0x7ADEF8D7, 0x7AEC2271, 0x7B04F957, 0x7B14F93E, - 0x7B241EDB, 0x7B3C1FB7, 0x7B5AF833, 0x7B681EAB, 0x7B800145, 0x7B92F9E8, - 0x7BA1112F, 0x7BC41E31, 0x7BD41FF7, 0x7BF01F32, 0x7C0C04EC, 0x7C2001CD, - 0x7C301F0B, 0x7C4EF99E, 0x7C5EF899, 0x7C6C0158, 0x7C7C1EB4, 0x7C940626, - 0x7CA801EC, 0x7CC01F2B, 0x7CDCFA72, 0x7A10FA40, 0x7CEEF8FB, 0x7D02F8DC, - 0x7D12F9D7, 0x7D200959, 0x7D3C020A, 0x7D4C1F20, 0x7D62F81F, 0x7D7114BE, - 0x7D96F8FD, 0x7B5AF831, 0x2BD6F805, 0x3842F81B, 0x7DA41F92, 0x7DC91938, - 0x7DEC1E5A, 0x625AF893, 0x7DFC0216, 0x7E0EF973, 0x7E200934, 0x7E3C01DA, - 0x7E54FAC6, 0x7E641F03, 0x7E82FA12, 0x7E941E8B, 0x7EA6FA06, 0x7EB4FA8C, - 0x7EC4F9A4, 0x163CF96F, 0x7ED41F87, 0x7EF804C1, 0x7F0EF99A, 0x7F1C1F3A, - 0x7F3AF8F8, 0x7F4C1F05, 0x7F681F78, 0x7F7C0FB9, 0x7F981E22, 0x7FA81FF2, - 0x7FC6F979, 0x7FD6F909, 0x11041FBB, 0x7FE43067, 0x8000F9FD, 0x80101F8B, - 0x8034F945, 0x804404F1, 0x80580164, 0x80681E71, 0x807AF819, 0x80881FCE, - 0x80A01FCC, 0x80B41EC3, 0x80CCFAA3, 0x80DEF932, 0x80EC1E24, 0x80FCF96C, - 0x810C022E, 0x811C1E2B, 0x812C0D4A, 0x814801F8, 0x28ECF928, 0x8158FA2F, - 0x81680F5C, 0x81843058, 0x81A01E2D, 0x81B0F934, 0x81C0F9D8, 0x81D0F9C2, - 0x81E2F9EF, 0x47AEF846, 0x81F0FA5A, 0x820030D6, 0x821C1F8D, 0x3A8C1FC9, - 0x8242F9F6, 0x8254F916, 0x8265D163, 0x50FEF8A7, 0x82981E1F, 0x82A81FD8, - 0x82BC1FE5, 0x82D01F04, 0x82EC0340, 0x57B8FA10, 0x82F8017D, 0x8309D1BE, - 0x833C0CC7, 0x83581FA3, 0x837EF951, 0x838C1E7E, 0x839C1F8F, 0x83C01EB5, - 0x83DAF824, 0x83EAF91F, 0x83FC1ED0, 0x8414FAD0, 0x8428016D, 0xCD4FA76, - 0x8438FA20, 0x8448F98A, 0x84581E10, 0x84680115, 0x1484FA5B, 0x2A4EF902, - 0x8478F912, 0x84880122, 0x849AF9A3, 0x84AAF8A2, 0x84B830F9, 0x84D40FAC, - 0x84F0F9C8, 0x8500F922, 0x85101E69, 0x8528014D, 0x85381F9B, 0x855C1E21, - 0x856CFB32, 0x85800177, 0x85901ED2, 0x85A80476, 0x85BC022B, 0x85D401D7, - 0x85EC0219, 0x85FC0228, 0x860C3062, 0x86281E56, 0x863804F2, 0x864EF963, - 0x865C0DDC, 0x867AF91C, 0x86880450, 0x869C1F38, 0x86B00229, 0x86C2FA00, - 0x86D0FA1D, 0x12D0FA44, 0x86E00136, 0x86F0F965, 0x8700F9F2, 0x53500389, - 0x87103065, 0x7B5AF832, 0x872CF90E, 0x873EF8B8, 0x8752F82C, 0x8762F992, - 0x87700107, 0x4BE0212B, 0x3234FA92, 0x87802241, 0x8798095C, 0x87B4F905, - 0x87C4F9A5, 0x87D6F95C, 0x87EAF8E3, 0x87FC0CC0, 0x881801F4, 0x88281F65, - 0x8846F967, 0x8856F8E1, 0x8864309E, 0x88800113, 0x8890020B, 0x88A01FAB, - 0x88C6F8D5, 0x266CFA69, 0x88D43079, 0x88F01F2F, 0x890C1EC8, 0x891CFB4B, - 0x89300B5C, 0x894EF817, 0x895C00FD, 0x896C040E, 0x89801E00, 0x8990017C, - 0x89A0F94C, 0x1B94FA96, 0x89B01E44, 0x89C01F7C, 0x89D4FB1D, 0x89E800F5, - 0x89F8226E, 0x8A08F997, 0x8A181FB6, 0x8A2EF9BD, 0x8A3EF835, 0x8A4EF867, - 0x8A5CFA4A, 0x8A6CFA59, 0x8A7CF972, 0x8A8EF92A, 0x1B94F970, 0x8A9C1FE4, - 0x8AB2F91D, 0x8AC6F80F, 0x8AD40A33, 0x8AF01F4A, 0x8B0EF965, 0x8B201F0C, - 0x2B2CF907, 0x8B3CF95A, 0x8B4C1ECE, 0x559EF84C, 0x8B5C0F78, 0x8B780F76, - 0x8B9400E0, 0x8BA40207, 0x8BB6F811, 0x8BC4F955, 0x8BD4F90B, 0x8BE41E4E, - 0x8BFC1FA2, 0x8C22F8C7, 0x8C301EB3, 0x8C48F903, 0x8C581E33, 0x8C681F10, - 0x8C7EF80B, 0x8C8C1E8A, 0x8C9CF902, 0x8CAD15BA, 0x8CD030FE, 0x8CEEF8E8, - 0x8CFCFA8D, 0x4F20FA62, 0x8D0C04E7, 0x8D20010E, 0x8D301EE5, 0x8D42F834, - 0x2CEF8E7, 0x8D540175, 0x8D64F9B5, 0x7A10FA8B, 0x8D76F83A, 0x8D840CCA, - 0x8DA01F70, 0x8DB4FA08, 0x8DC6F9D4, 0x8DD40147, 0x8DE4FA9F, 0x4D40FA68, - 0x8DF4F9EB, 0x1188FA93, 0x8E06F9D9, 0x8E181EAD, 0x8E30FA39, 0x8E42F9C2, - 0x8E52F9B1, 0x8E6422ED, 0x8E7EF83C, 0x8E8C1EBD, 0x8E9CF901, 0x8EAEF917, - 0x3830F95F, 0x8EBCFAD4, 0x8ECC00F4, 0x6D54F95D, 0x8EDEF970, 0x8EEC0387, - 0x3F4AF80E, 0x8EF81E05, 0x8F081FE8, 0x8EBEF949, 0x8F1EF8C1, 0x8F2EF954, - 0x8F40F938, 0x8F52F98F, 0x8F601E76, 0x8F72F886, 0x8F801F3D, 0x8F9C0129, - 0x8FAC1E57, 0x8FBC0117, 0x8FCEF81E, 0x8FDCF9C0, 0x8FEC1ECF, 0x8FFEF989, - 0x9010FAC5, 0x570EF82B, 0x9020F9F4, 0x9032F9B5, 0x436CFACD, 0x9042F9DC, - 0x9050F913, 0x90601E87, 0x9072F8EE, 0x65301FDB, 0x9080016A, 0x9092FA02, - 0x314FAC8, 0x90A2F8E5, 0x90B0FA9D, 0x90C03056, 0x90DC0FA7, 0x90F81F00, - 0x910C0215, 0x911CF97D, 0x912C2279, 0x91441FC4, 0x91602244, 0x9178F930, - 0x91881F50, 0x919CFAAF, 0x91AC1EF9, 0x91BC0209, 0x5A8EF9DF, 0x179AF8A3, - 0x91CCF949, 0x91DEF910, 0x91F01E5D, 0x9209D1BD, 0x923EF8B3, 0x924C0403, - 0x926009DF, 0x927DD15F, 0x92A2F97C, 0x92B4F9E9, 0x92C514BB, 0x92EAF9D8, - 0x92FEF9F5, 0x930C01F9, 0x931C30DD, 0x93380101, 0x934AF9AD, 0x935EF95A, - 0x16681F7D, -}; - -#define NFC_COMP_LEVEL_COUNT 3 - -static const uint16_t _swift_stdlib_nfc_comp_sizes[3] = { - 0x40, 0x40, 0x40, -}; - -static const uint64_t _swift_stdlib_nfc_comp_keys0[1] = { - 0x92AE59250292839C, -}; - -static const uint64_t _swift_stdlib_nfc_comp_keys1[1] = { - 0xB0087D6521441206, -}; - -static const uint64_t _swift_stdlib_nfc_comp_keys2[1] = { - 0x500C890402981802, -}; - -static const uint64_t * const _swift_stdlib_nfc_comp_keys[3] = { - _swift_stdlib_nfc_comp_keys0, _swift_stdlib_nfc_comp_keys1, - _swift_stdlib_nfc_comp_keys2, -}; - -static const uint16_t _swift_stdlib_nfc_comp_ranks0[1] = { - 0x0, -}; - -static const uint16_t _swift_stdlib_nfc_comp_ranks1[1] = { - 0x1A, -}; - -static const uint16_t _swift_stdlib_nfc_comp_ranks2[1] = { - 0x30, -}; - -static const uint16_t * const _swift_stdlib_nfc_comp_ranks[3] = { - _swift_stdlib_nfc_comp_ranks0, _swift_stdlib_nfc_comp_ranks1, - _swift_stdlib_nfc_comp_ranks2, -}; - -static const uint32_t _swift_stdlib_nfc_comp0[15] = { - 0x1E0030F, 0x37E0041, 0x37E0045, 0x37E0049, 0x37A004F, 0x37C0052, 0x37E0055, - 0x3400061, 0x3400065, 0x3400069, 0x33C006F, 0x33E0072, 0x3400075, 0x40474, - 0x40475, -}; - -static const uint32_t _swift_stdlib_nfc_comp1[4] = { - 0x8110BA, 0x31099, 0x3109B, 0xD10A5, -}; - -static const uint32_t _swift_stdlib_nfc_comp2[45] = { - 0x5A00304, 0x17E0041, 0x19A0045, 0x3BB20047, 0x1C20049, 0x1FA004F, 0x22A0055, - 0x3B20059, 0x1400061, 0x15C0065, 0x3B740067, 0x1840069, 0x1BC006F, 0x1EC0075, - 0x3740079, 0x23400C4, 0x23800C6, 0x2AE00D5, 0x2A800D6, 0x1F200DC, 0x1F600E4, - 0x1FA00E6, 0x27000F5, 0x26A00F6, 0x1B400FC, 0x401EA, 0x401EB, 0x808C0226, - 0x808C0227, 0x4022E, 0x4022F, 0x38500391, 0x38800399, 0x388803A5, 0x380003B1, - 0x383003B9, 0x383803C5, 0x1940418, 0x1960423, 0x1560438, 0x1580443, 0x41E36, - 0x41E37, 0x41E5A, 0x41E5B, -}; - -static const uint32_t _swift_stdlib_nfc_comp3[2] = { - 0x400B3E, 0x80B47, -}; - -static const uint32_t _swift_stdlib_nfc_comp4[45] = { - 0x5A00338, 0x4464003C, 0x4446003D, 0x4462003E, 0x142190, 0x122192, 0x342194, - 0x800621D0, 0x800621D2, 0x800C21D4, 0x22203, 0x22208, 0x2220B, 0x22223, - 0x22225, 0xA223C, 0x22243, 0x42245, 0x22248, 0x40224D, 0x22261, 0x182264, - 0x182265, 0x42272, 0x42273, 0x42276, 0x42277, 0xC227A, 0xC227B, 0xC8227C, - 0xC8227D, 0x42282, 0x42283, 0x42286, 0x42287, 0xA22291, 0xA22292, 0x1422A2, - 0xA22A8, 0xA22A9, 0x822AB, 0x7022B2, 0x7022B3, 0x7022B4, 0x7022B5, -}; - -static const uint32_t _swift_stdlib_nfc_comp5[2] = { - 0x400C56, 0x40C46, -}; - -static const uint32_t _swift_stdlib_nfc_comp6[2] = { - 0x4009BE, 0x809C7, -}; - -static const uint32_t _swift_stdlib_nfc_comp7[17] = { - 0x2200314, 0x36F00391, 0x37080395, 0x37240397, 0x37400399, 0x3754039F, - 0x389603A1, 0x376803A5, 0x378003A9, 0x36A003B1, 0x36B803B5, 0x36D403B7, - 0x36F003B9, 0x370403BF, 0x384803C1, 0x371803C5, 0x373003C9, -}; - -static const uint32_t _swift_stdlib_nfc_comp8[47] = { - 0x5E00307, 0x3CA0041, 0x3B800042, 0x18E0043, 0x3B8C0044, 0x1A20045, - 0x3BB00046, 0x1B20047, 0x3BB40048, 0x1CE0049, 0x3BE6004D, 0x3BEC004E, - 0x3BE004F, 0x3C0C0050, 0x3C0C0052, 0x3C1A0053, 0x3C2C0054, 0x3C5E0057, - 0x3C640058, 0x3C6A0059, 0x242005A, 0x38C0061, 0x3B420062, 0x1500063, - 0x3B4E0064, 0x1640065, 0x3B720066, 0x1740067, 0x3B760068, 0x3BA8006D, - 0x3BAE006E, 0x380006F, 0x3BCE0070, 0x3BCE0072, 0x3BDC0073, 0x3BEE0074, - 0x3C200077, 0x3C260078, 0x3C2C0079, 0x204007A, 0x3A14015A, 0x3A14015B, - 0x3A0C0160, 0x3A0C0161, 0x3A38017F, 0xC1E62, 0xC1E63, -}; - -static const uint32_t _swift_stdlib_nfc_comp9[5] = { - 0xA00326, 0x38A0053, 0x38C0054, 0x34C0073, 0x34E0074, -}; - -static const uint32_t _swift_stdlib_nfc_comp10[2] = { - 0x400CD6, 0x40CC6, -}; - -static const uint32_t _swift_stdlib_nfc_comp11[7] = { - 0xE00330, 0x3BAA0045, 0x3BC60049, 0x3C3E0055, 0x3B6C0065, 0x3B880069, - 0x3C000075, -}; - -static const uint32_t _swift_stdlib_nfc_comp12[3] = { - 0x600DCA, 0x20DD9, 0x20DDC, -}; - -static const uint32_t _swift_stdlib_nfc_comp13[2] = { - 0x4114B0, 0x714B9, -}; - -static const uint32_t _swift_stdlib_nfc_comp14[3] = { - 0x611127, 0x80071131, 0x80071132, -}; - -static const uint32_t _swift_stdlib_nfc_comp15[2] = { - 0x400DDF, 0xA0DD9, -}; - -static const uint32_t _swift_stdlib_nfc_comp16[38] = { - 0x4C0030C, 0x3180041, 0x1920043, 0x1940044, 0x1AA0045, 0x33E0047, 0x3AC0048, - 0x30C0049, 0x33A004B, 0x1E2004C, 0x1F2004E, 0x304004F, 0x20C0052, 0x21A0053, - 0x2200054, 0x2FC0055, 0x246005A, 0x2DA0061, 0x1540063, 0x1560064, 0x16C0065, - 0x3000067, 0x36E0068, 0x2CE0069, 0x30C006A, 0x2FC006B, 0x1A4006C, 0x1B4006E, - 0x2C6006F, 0x1CE0072, 0x1DC0073, 0x1E20074, 0x2BE0075, 0x208007A, 0x1FA00DC, - 0x1BC00FC, 0x6E01B7, 0x81460292, -}; - -static const uint32_t _swift_stdlib_nfc_comp17[64] = { - 0x8000345, 0x38560391, 0x386A0397, 0x38A603A9, 0x381003AC, 0x382C03AE, - 0x380403B1, 0x381803B7, 0x385403C9, 0x384C03CE, 0x1001F00, 0x1001F01, - 0x1001F02, 0x1001F03, 0x1001F04, 0x1001F05, 0x1001F06, 0x1001F07, 0x1001F08, - 0x1001F09, 0x1001F0A, 0x1001F0B, 0x1001F0C, 0x1001F0D, 0x1001F0E, 0x1001F0F, - 0xE01F20, 0xE01F21, 0xE01F22, 0xE01F23, 0xE01F24, 0xE01F25, 0xE01F26, - 0xE01F27, 0xE01F28, 0xE01F29, 0xE01F2A, 0xE01F2B, 0xE01F2C, 0xE01F2D, - 0xE01F2E, 0xE01F2F, 0x801F60, 0x801F61, 0x801F62, 0x801F63, 0x801F64, - 0x801F65, 0x801F66, 0x801F67, 0x801F68, 0x801F69, 0x801F6A, 0x801F6B, - 0x801F6C, 0x801F6D, 0x801F6E, 0x801F6F, 0x841F70, 0x9C1F74, 0xEC1F7C, 0x21FB6, - 0x21FC6, 0x21FF6, -}; - -static const uint32_t _swift_stdlib_nfc_comp18[5] = { - 0xA0031B, 0x2A2004F, 0x2B40055, 0x264006F, 0x2760075, -}; - -static const uint32_t _swift_stdlib_nfc_comp19[3] = { - 0x600BD7, 0x40B92, 0xC0BC6, -}; - -static const uint32_t _swift_stdlib_nfc_comp20[2] = { - 0x400CC2, 0x80CC6, -}; - -static const uint32_t _swift_stdlib_nfc_comp21[11] = { - 0x160309A, 0x4306F, 0x43072, 0x43075, 0x43078, 0x4307B, 0x430CF, 0x430D2, - 0x430D5, 0x430D8, 0x430DB, -}; - -static const uint32_t _swift_stdlib_nfc_comp22[85] = { - 0xAA00300, 0xFE0041, 0x1060045, 0x1060049, 0x354004E, 0x106004F, 0x1080055, - 0x3C520057, 0x3D320059, 0xFE0061, 0x1060065, 0x1060069, 0x316006E, 0x106006F, - 0x1080075, 0x3C140077, 0x3CF40079, 0x3E8A00A8, 0x3BC800C2, 0x3BEC00CA, - 0x3BFC00D4, 0x1FE00DC, 0x3B8A00E2, 0x3BAE00EA, 0x3BBE00F4, 0x1C000FC, - 0x3B5C0102, 0x3B5C0103, 0x3A040112, 0x3A040113, 0x3A08014C, 0x3A08014D, - 0x3A7801A0, 0x3A7801A1, 0x3A7601AF, 0x3A7601B0, 0x38520391, 0x38660395, - 0x38660397, 0x38820399, 0x38B2039F, 0x388A03A5, 0x38A203A9, 0x377E03B1, - 0x377A03B5, 0x377A03B7, 0x377A03B9, 0x377203BF, 0x376A03C5, 0x376603C9, - 0x381003CA, 0x382E03CB, 0x802A0415, 0x80160418, 0x360435, 0x4A0438, 0x41F00, - 0x41F01, 0x41F08, 0x41F09, 0x41F10, 0x41F11, 0x41F18, 0x41F19, 0x41F20, - 0x41F21, 0x41F28, 0x41F29, 0x41F30, 0x41F31, 0x41F38, 0x41F39, 0x41F40, - 0x41F41, 0x41F48, 0x41F49, 0x41F50, 0x41F51, 0x41F59, 0x41F60, 0x41F61, - 0x41F68, 0x41F69, 0x1C1FBF, 0x80421FFE, -}; - -static const uint32_t _swift_stdlib_nfc_comp23[55] = { - 0x6E00308, 0x1060041, 0x10C0045, 0x3BBC0048, 0x10C0049, 0x10E004F, 0x10E0055, - 0x3C5A0057, 0x3C680058, 0x23E0059, 0x1060061, 0x10C0065, 0x3B7E0068, - 0x10C0069, 0x10E006F, 0x3C460074, 0x10E0075, 0x3C1C0077, 0x3C2A0078, - 0x10C0079, 0x3AF200D5, 0x3AB400F5, 0x3A20016A, 0x3A20016B, 0x220399, 0xC03A5, - 0x2203B9, 0xC03C5, 0x403D2, 0x20406, 0x1840410, 0x80280415, 0x18C0416, - 0x18E0417, 0x1980418, 0x190041E, 0x19A0423, 0x19A0427, 0x19A042B, 0x17E042D, - 0x1460430, 0x380435, 0x14E0436, 0x1500437, 0x15A0438, 0x152043E, 0x15C0443, - 0x15C0447, 0x15C044B, 0x140044D, 0x20456, 0x404D8, 0x404D9, 0x404E8, 0x404E9, -}; - -static const uint32_t _swift_stdlib_nfc_comp24[2] = { - 0x4009D7, 0xA09C7, -}; - -static const uint32_t _swift_stdlib_nfc_comp25[30] = { - 0x3C00342, 0x3E3200A8, 0x380A03B1, 0x381E03B7, 0x383A03B9, 0x384203C5, - 0x385A03C9, 0x381A03CA, 0x383803CB, 0xC1F00, 0xC1F01, 0xC1F08, 0xC1F09, - 0xC1F20, 0xC1F21, 0xC1F28, 0xC1F29, 0xC1F30, 0xC1F31, 0xC1F38, 0xC1F39, - 0xC1F50, 0xC1F51, 0xC1F59, 0xC1F60, 0xC1F61, 0xC1F68, 0xC1F69, 0x201FBF, - 0x803E1FFE, -}; - -static const uint32_t _swift_stdlib_nfc_comp26[3] = { - 0x6115AF, 0x515B8, 0x515B9, -}; - -static const uint32_t _swift_stdlib_nfc_comp27[2] = { - 0x400B56, 0x20B47, -}; - -static const uint32_t _swift_stdlib_nfc_comp28[49] = { - 0x6203099, 0x9C3046, 0x2304B, 0x2304D, 0x2304F, 0x23051, 0x23053, 0x23055, - 0x23057, 0x23059, 0x2305B, 0x2305D, 0x2305F, 0x23061, 0x23064, 0x23066, - 0x23068, 0x2306F, 0x23072, 0x23075, 0x23078, 0x2307B, 0x2309D, 0x9C30A6, - 0x230AB, 0x230AD, 0x230AF, 0x230B1, 0x230B3, 0x230B5, 0x230B7, 0x230B9, - 0x230BB, 0x230BD, 0x230BF, 0x230C1, 0x230C4, 0x230C6, 0x230C8, 0x230CF, - 0x230D2, 0x230D5, 0x230D8, 0x230DB, 0x1030EF, 0x1030F0, 0x1030F1, 0x1030F2, - 0x230FD, -}; - -static const uint32_t _swift_stdlib_nfc_comp29[3] = { - 0x60032E, 0x3BC40048, 0x3B860068, -}; - -static const uint32_t _swift_stdlib_nfc_comp30[2] = { - 0x400D57, 0xC0D46, -}; - -static const uint32_t _swift_stdlib_nfc_comp31[2] = { - 0x411930, 0x71935, -}; - -static const uint32_t _swift_stdlib_nfc_comp32[25] = { - 0x3200309, 0x3CC20041, 0x3CEA0045, 0x3CFE0049, 0x3CFE004F, 0x3D220055, - 0x3D3A0059, 0x3C840061, 0x3CAC0065, 0x3CC00069, 0x3CC0006F, 0x3CE40075, - 0x3CFC0079, 0x3BCC00C2, 0x3BF000CA, 0x3C0000D4, 0x3B8E00E2, 0x3BB200EA, - 0x3BC200F4, 0x3B600102, 0x3B600103, 0x3A7C01A0, 0x3A7C01A1, 0x3A7A01AF, - 0x3A7A01B0, -}; - -static const uint32_t _swift_stdlib_nfc_comp33[2] = { - 0x40102E, 0x21025, -}; - -static const uint32_t _swift_stdlib_nfc_comp34[2] = { - 0x400653, 0x800A0627, -}; - -static const uint32_t _swift_stdlib_nfc_comp35[2] = { - 0x41133E, 0x91347, -}; - -static const uint32_t _swift_stdlib_nfc_comp36[23] = { - 0x2E00327, 0x1080043, 0x3B980044, 0x3C60045, 0x1B60047, 0x3BC00048, 0x1D6004B, - 0x1DE004C, 0x1EE004E, 0x2080052, 0x2160053, 0x21C0054, 0x1080063, 0x3B5A0064, - 0x3880065, 0x1780067, 0x3B820068, 0x198006B, 0x1A0006C, 0x1B0006E, 0x1CA0072, - 0x1D80073, 0x1DE0074, -}; - -static const uint32_t _swift_stdlib_nfc_comp37[118] = { - 0xEC00301, 0x1000041, 0x1860043, 0x1080045, 0x35A0047, 0x1080049, 0x3BCA004B, - 0x1DA004C, 0x3BE2004D, 0x1EA004E, 0x108004F, 0x3C080050, 0x2040052, 0x20E0053, - 0x10A0055, 0x3C560057, 0x1080059, 0x23E005A, 0x1000061, 0x1480063, 0x1080065, - 0x31C0067, 0x1080069, 0x3B8C006B, 0x19C006C, 0x3BA4006D, 0x1AC006E, 0x108006F, - 0x3BCA0070, 0x1C60072, 0x1D00073, 0x10A0075, 0x3C180077, 0x1080079, 0x200007A, - 0x5BA00A8, 0x3BC400C2, 0x26A00C5, 0x26C00C6, 0x3A8200C7, 0x3BE800CA, - 0x3ABE00CF, 0x3BF800D4, 0x3AEE00D5, 0x24C00D8, 0x1F600DC, 0x3B8600E2, - 0x22C00E5, 0x22E00E6, 0x3A4400E7, 0x3BAA00EA, 0x3A8000EF, 0x3BBA00F4, - 0x3AB000F5, 0x20E00F8, 0x1B800FC, 0x3B580102, 0x3B580103, 0x3A080112, - 0x3A080113, 0x3A0C014C, 0x3A0C014D, 0x3A200168, 0x3A200169, 0x3A7401A0, - 0x3A7401A1, 0x3A7201AF, 0x3A7201B0, 0x80160391, 0x801A0395, 0x801C0397, - 0x801E0399, 0x8026039F, 0x802E03A5, 0x803403A9, 0x800A03B1, 0x801003B5, - 0x801203B7, 0x801403B9, 0x1A03BF, 0x1003C5, 0xA03C9, 0x807403CA, 0x803603CB, - 0x203D2, 0x80200413, 0x801C041A, 0x400433, 0x44043A, 0x81F00, 0x81F01, - 0x81F08, 0x81F09, 0x81F10, 0x81F11, 0x81F18, 0x81F19, 0x81F20, 0x81F21, - 0x81F28, 0x81F29, 0x81F30, 0x81F31, 0x81F38, 0x81F39, 0x81F40, 0x81F41, - 0x81F48, 0x81F49, 0x81F50, 0x81F51, 0x81F59, 0x81F60, 0x81F61, 0x81F68, - 0x81F69, 0x1E1FBF, 0x80401FFE, -}; - -static const uint32_t _swift_stdlib_nfc_comp38[29] = { - 0x3A00303, 0x1040041, 0x3CEE0045, 0x1BE0049, 0x106004E, 0x10C004F, 0x2260055, - 0x3C4C0056, 0x3D3E0059, 0x1040061, 0x3CB00065, 0x1800069, 0x106006E, - 0x10C006F, 0x1E80075, 0x3C0E0076, 0x3D000079, 0x3BD000C2, 0x3BF400CA, - 0x3C0400D4, 0x3B9200E2, 0x3BB600EA, 0x3BC600F4, 0x3B640102, 0x3B640103, - 0x3A8001A0, 0x3A8001A1, 0x3A7E01AF, 0x3A7E01B0, -}; - -static const uint32_t _swift_stdlib_nfc_comp39[2] = { - 0x4114BA, 0x514B9, -}; - -static const uint32_t _swift_stdlib_nfc_comp40[2] = { - 0x4114BD, 0xB14B9, -}; - -static const uint32_t _swift_stdlib_nfc_comp41[7] = { - 0xE0030B, 0x202004F, 0x2360055, 0x1C4006F, 0x1F80075, 0x19E0423, 0x1600443, -}; - -static const uint32_t _swift_stdlib_nfc_comp42[2] = { - 0x400655, 0x80040627, -}; - -static const uint32_t _swift_stdlib_nfc_comp43[13] = { - 0x1A0032D, 0x3B9C0044, 0x3BA60045, 0x3BE0004C, 0x3BF8004E, 0x3C380054, - 0x3C420055, 0x3B5E0064, 0x3B680065, 0x3BA2006C, 0x3BBA006E, 0x3BFA0074, - 0x3C040075, -}; - -static const uint32_t _swift_stdlib_nfc_comp44[33] = { - 0x4200306, 0x1820041, 0x19E0045, 0x1AE0047, 0x1C60049, 0x1FE004F, 0x22E0055, - 0x1440061, 0x1600065, 0x1700067, 0x1880069, 0x1C0006F, 0x1F00075, 0x37E80228, - 0x37E80229, 0x384E0391, 0x387E0399, 0x388603A5, 0x37FE03B1, 0x382E03B9, - 0x383603C5, 0x1800410, 0x1820415, 0x1560416, 0x20418, 0x802A0423, 0x1420430, - 0x1440435, 0x1180436, 0x20438, 0x360443, 0x2C1EA0, 0x2C1EA1, -}; - -static const uint32_t _swift_stdlib_nfc_comp45[3] = { - 0x600324, 0x3C3A0055, 0x3BFC0075, -}; - -static const uint32_t _swift_stdlib_nfc_comp46[4] = { - 0x80093C, 0x20928, 0x20930, 0x20933, -}; - -static const uint32_t _swift_stdlib_nfc_comp47[2] = { - 0x400B57, 0xA0B47, -}; - -static const uint32_t _swift_stdlib_nfc_comp48[7] = { - 0xE00654, 0x80080627, 0x80480648, 0x8048064A, 0x206C1, 0x206D2, 0x802A06D5, -}; - -static const uint32_t _swift_stdlib_nfc_comp49[3] = { - 0x600BBE, 0x80BC6, 0x80BC7, -}; - -static const uint32_t _swift_stdlib_nfc_comp50[2] = { - 0x400DCF, 0x60DD9, -}; - -static const uint32_t _swift_stdlib_nfc_comp51[7] = { - 0xE0030A, 0x1080041, 0x2320055, 0x1080061, 0x1F40075, 0x3C420077, 0x3C400079, -}; - -static const uint32_t _swift_stdlib_nfc_comp52[13] = { - 0x1A00311, 0x3820041, 0x3820045, 0x3820049, 0x37E004F, 0x3800052, 0x3820055, - 0x3440061, 0x3440065, 0x3440069, 0x340006F, 0x3420072, 0x3440075, -}; - -static const uint32_t _swift_stdlib_nfc_comp53[15] = { - 0x1E00313, 0x36EE0391, 0x37060395, 0x37220397, 0x373E0399, 0x3752039F, - 0x377E03A9, 0x369E03B1, 0x36B603B5, 0x36D203B7, 0x36EE03B9, 0x370203BF, - 0x384603C1, 0x371603C5, 0x372E03C9, -}; - -static const uint32_t _swift_stdlib_nfc_comp54[18] = { - 0x2400331, 0x3B880042, 0x3B940044, 0x3BD2004B, 0x3BDC004C, 0x3BF4004E, - 0x3C180052, 0x3C340054, 0x3C74005A, 0x3B4A0062, 0x3B560064, 0x3C5C0068, - 0x3B94006B, 0x3B9E006C, 0x3BB6006E, 0x3BDA0072, 0x3BF60074, 0x3C36007A, -}; - -static const uint32_t _swift_stdlib_nfc_comp55[43] = { - 0x5600323, 0x3CBE0041, 0x3B840042, 0x3B900044, 0x3CE60045, 0x3BB80048, - 0x3D020049, 0x3BCE004B, 0x3BD4004C, 0x3BEA004D, 0x3BF0004E, 0x3CFA004F, - 0x3C100052, 0x3C1E0053, 0x3C300054, 0x3D1E0055, 0x3C500056, 0x3C620057, - 0x3D360059, 0x3C70005A, 0x3C800061, 0x3B460062, 0x3B520064, 0x3CA80065, - 0x3B7A0068, 0x3CC40069, 0x3B90006B, 0x3B96006C, 0x3BAC006D, 0x3BB2006E, - 0x3CBC006F, 0x3BD20072, 0x3BE00073, 0x3BF20074, 0x3CE00075, 0x3C120076, - 0x3C240077, 0x3CF80079, 0x3C32007A, 0x3A8401A0, 0x3A8401A1, 0x3A8201AF, - 0x3A8201B0, -}; - -static const uint32_t _swift_stdlib_nfc_comp56[12] = { - 0x1801B35, 0x21B05, 0x21B07, 0x21B09, 0x21B0B, 0x21B0D, 0x21B11, 0x21B3A, - 0x21B3C, 0x41B3E, 0x41B3F, 0x21B42, -}; - -static const uint32_t _swift_stdlib_nfc_comp57[11] = { - 0x1600328, 0x1860041, 0x1A60045, 0x1CA0049, 0x336004F, 0x23A0055, 0x1480061, - 0x1680065, 0x18C0069, 0x2F8006F, 0x1FC0075, -}; - -static const uint32_t _swift_stdlib_nfc_comp58[33] = { - 0x4200302, 0x1020041, 0x18A0043, 0x10A0045, 0x1AA0047, 0x1B80048, 0x10A0049, - 0x1D4004A, 0x10A004F, 0x2120053, 0x10C0055, 0x23A0057, 0x23A0059, 0x3C6C005A, - 0x1020061, 0x14C0063, 0x10A0065, 0x16C0067, 0x17A0068, 0x10A0069, 0x196006A, - 0x10A006F, 0x1D40073, 0x10C0075, 0x1FC0077, 0x1FC0079, 0x3C2E007A, 0x181EA0, - 0x181EA1, 0x1C1EB8, 0x1C1EB9, 0x181ECC, 0x181ECD, -}; - -static const uint32_t _swift_stdlib_nfc_comp59[3] = { - 0x600D3E, 0x80D46, 0x80D47, -}; - -static const uint32_t _swift_stdlib_nfc_comp60[2] = { - 0x411357, 0xB1347, -}; - -static const uint32_t _swift_stdlib_nfc_comp61[4] = { - 0x800CD5, 0x20CBF, 0x20CC6, 0x20CCA, -}; - -static const uint32_t _swift_stdlib_nfc_comp62[3] = { - 0x600325, 0x3B7E0041, 0x3B400061, -}; - -static const uint32_t * const _swift_stdlib_nfc_comp_indices[63] = { - _swift_stdlib_nfc_comp0, _swift_stdlib_nfc_comp1, _swift_stdlib_nfc_comp2, - _swift_stdlib_nfc_comp3, _swift_stdlib_nfc_comp4, _swift_stdlib_nfc_comp5, - _swift_stdlib_nfc_comp6, _swift_stdlib_nfc_comp7, _swift_stdlib_nfc_comp8, - _swift_stdlib_nfc_comp9, _swift_stdlib_nfc_comp10, _swift_stdlib_nfc_comp11, - _swift_stdlib_nfc_comp12, _swift_stdlib_nfc_comp13, _swift_stdlib_nfc_comp14, - _swift_stdlib_nfc_comp15, _swift_stdlib_nfc_comp16, _swift_stdlib_nfc_comp17, - _swift_stdlib_nfc_comp18, _swift_stdlib_nfc_comp19, _swift_stdlib_nfc_comp20, - _swift_stdlib_nfc_comp21, _swift_stdlib_nfc_comp22, _swift_stdlib_nfc_comp23, - _swift_stdlib_nfc_comp24, _swift_stdlib_nfc_comp25, _swift_stdlib_nfc_comp26, - _swift_stdlib_nfc_comp27, _swift_stdlib_nfc_comp28, _swift_stdlib_nfc_comp29, - _swift_stdlib_nfc_comp30, _swift_stdlib_nfc_comp31, _swift_stdlib_nfc_comp32, - _swift_stdlib_nfc_comp33, _swift_stdlib_nfc_comp34, _swift_stdlib_nfc_comp35, - _swift_stdlib_nfc_comp36, _swift_stdlib_nfc_comp37, _swift_stdlib_nfc_comp38, - _swift_stdlib_nfc_comp39, _swift_stdlib_nfc_comp40, _swift_stdlib_nfc_comp41, - _swift_stdlib_nfc_comp42, _swift_stdlib_nfc_comp43, _swift_stdlib_nfc_comp44, - _swift_stdlib_nfc_comp45, _swift_stdlib_nfc_comp46, _swift_stdlib_nfc_comp47, - _swift_stdlib_nfc_comp48, _swift_stdlib_nfc_comp49, _swift_stdlib_nfc_comp50, - _swift_stdlib_nfc_comp51, _swift_stdlib_nfc_comp52, _swift_stdlib_nfc_comp53, - _swift_stdlib_nfc_comp54, _swift_stdlib_nfc_comp55, _swift_stdlib_nfc_comp56, - _swift_stdlib_nfc_comp57, _swift_stdlib_nfc_comp58, _swift_stdlib_nfc_comp59, - _swift_stdlib_nfc_comp60, _swift_stdlib_nfc_comp61, _swift_stdlib_nfc_comp62, -}; - -#endif // #ifndef NORMALIZATION_DATA_H diff --git a/Sources/_CUnicode/UnicodeGrapheme.c b/Sources/_CUnicode/UnicodeGrapheme.c deleted file mode 100644 index a1aff30cc..000000000 --- a/Sources/_CUnicode/UnicodeGrapheme.c +++ /dev/null @@ -1,72 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#include "Common/GraphemeData.h" -#include "include/UnicodeData.h" - -SWIFT_CC -uint8_t _swift_stdlib_getGraphemeBreakProperty(uint32_t scalar) { - int low = 0; - int high = GRAPHEME_BREAK_DATA_COUNT - 1; - - while (high >= low) { - int idx = low + (high - low) / 2; - - const uint32_t entry = _swift_stdlib_graphemeBreakProperties[idx]; - - // Shift the enum and range count out of the value. - uint32_t lower = (entry << 11) >> 11; - - // Shift the enum out first, then shift out the scalar value. - uint32_t upper = lower + ((entry << 3) >> 24); - - // Shift everything out. - uint8_t enumValue = (uint8_t)(entry >> 29); - - // Special case: extendedPictographic who used an extra bit for the range. - if (enumValue == 5) { - upper = lower + ((entry << 2) >> 23); - } - - if (scalar >= lower && scalar <= upper) { - return enumValue; - } - - if (scalar > upper) { - low = idx + 1; - continue; - } - - if (scalar < lower) { - high = idx - 1; - continue; - } - } - - // If we made it out here, then our scalar was not found in the grapheme - // array (this occurs when a scalar doesn't map to any grapheme break - // property). Return the max value here to indicate .any. - return 0xFF; -} - -SWIFT_CC -_Bool _swift_stdlib_isLinkingConsonant(uint32_t scalar) { - intptr_t idx = _swift_stdlib_getScalarBitArrayIdx(scalar, - _swift_stdlib_linkingConsonant, - _swift_stdlib_linkingConsonant_ranks); - - if (idx == INTPTR_MAX) { - return false; - } - - return true; -} diff --git a/Sources/_CUnicode/UnicodeNormalization.c b/Sources/_CUnicode/UnicodeNormalization.c deleted file mode 100644 index 6c7abfc81..000000000 --- a/Sources/_CUnicode/UnicodeNormalization.c +++ /dev/null @@ -1,116 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#if defined(__APPLE__) -#include "Apple/NormalizationData.h" -#else -#include "Common/NormalizationData.h" -#endif - -#include "include/UnicodeData.h" - -SWIFT_CC -uint16_t _swift_stdlib_getNormData(uint32_t scalar) { - // Fast Path: ASCII and some latiny scalars are very basic and have no - // normalization properties. - if (scalar < 0xC0) { - return 0; - } - - intptr_t dataIdx = _swift_stdlib_getScalarBitArrayIdx(scalar, - _swift_stdlib_normData, - _swift_stdlib_normData_ranks); - - // If we don't have an index into the data indices, then this scalar has no - // normalization information. - if (dataIdx == INTPTR_MAX) { - return 0; - } - - const uint8_t scalarDataIdx = _swift_stdlib_normData_data_indices[dataIdx]; - return _swift_stdlib_normData_data[scalarDataIdx]; -} - -SWIFT_CC -const uint8_t *_swift_stdlib_nfd_decompositions(void) { - return _swift_stdlib_nfd_decomp; -} - -SWIFT_CC -uint32_t _swift_stdlib_getDecompositionEntry(uint32_t scalar) { - intptr_t levelCount = NFD_DECOMP_LEVEL_COUNT; - intptr_t decompIdx = _swift_stdlib_getMphIdx(scalar, levelCount, - _swift_stdlib_nfd_decomp_keys, - _swift_stdlib_nfd_decomp_ranks, - _swift_stdlib_nfd_decomp_sizes); - - return _swift_stdlib_nfd_decomp_indices[decompIdx]; -} - -SWIFT_CC -uint32_t _swift_stdlib_getComposition(uint32_t x, uint32_t y) { - intptr_t levelCount = NFC_COMP_LEVEL_COUNT; - intptr_t compIdx = _swift_stdlib_getMphIdx(y, levelCount, - _swift_stdlib_nfc_comp_keys, - _swift_stdlib_nfc_comp_ranks, - _swift_stdlib_nfc_comp_sizes); - const uint32_t *array = _swift_stdlib_nfc_comp_indices[compIdx]; - - // Ensure that the first element in this array is equal to our y scalar. - const uint32_t realY = (array[0] << 11) >> 11; - - if (y != realY) { - return UINT32_MAX; - } - - const uint32_t count = array[0] >> 21; - - uint32_t low = 1; - uint32_t high = count - 1; - - while (high >= low) { - uint32_t idx = low + (high - low) / 2; - - const uint32_t entry = array[idx]; - - // Shift the range count out of the scalar. - const uint32_t lower = (entry << 15) >> 15; - - _Bool isNegative = entry >> 31; - uint32_t rangeCount = (entry << 1) >> 18; - - if (isNegative) { - rangeCount = -rangeCount; - } - - const uint32_t composed = lower + rangeCount; - - if (x == lower) { - return composed; - } - - if (x > lower) { - low = idx + 1; - continue; - } - - if (x < lower) { - high = idx - 1; - continue; - } - } - - // If we made it out here, then our scalar was not found in the composition - // array. - // Return the max here to indicate that we couldn't find one. - return UINT32_MAX; -} diff --git a/Sources/_CUnicode/include/UnicodeData.h b/Sources/_CUnicode/include/UnicodeData.h index c9437868c..eec0035fd 100644 --- a/Sources/_CUnicode/include/UnicodeData.h +++ b/Sources/_CUnicode/include/UnicodeData.h @@ -32,32 +32,6 @@ intptr_t _swift_stdlib_getScalarBitArrayIdx(uint32_t scalar, const uint64_t *bitArrays, const uint16_t *ranks); -//===----------------------------------------------------------------------===// -// Normalization -//===----------------------------------------------------------------------===// - -SWIFT_CC -uint16_t _swift_stdlib_getNormData(uint32_t scalar); - -SWIFT_CC -const uint8_t *_swift_stdlib_nfd_decompositions(void); - -SWIFT_CC -uint32_t _swift_stdlib_getDecompositionEntry(uint32_t scalar); - -SWIFT_CC -uint32_t _swift_stdlib_getComposition(uint32_t x, uint32_t y); - -//===----------------------------------------------------------------------===// -// Grapheme Breaking -//===----------------------------------------------------------------------===// - -SWIFT_CC -uint8_t _swift_stdlib_getGraphemeBreakProperty(uint32_t scalar); - -SWIFT_CC -_Bool _swift_stdlib_isLinkingConsonant(uint32_t scalar); - //===----------------------------------------------------------------------===// // Scalar Props //===----------------------------------------------------------------------===// diff --git a/Sources/_StringProcessing/Unicode/Data.swift b/Sources/_StringProcessing/Unicode/Data.swift deleted file mode 100644 index 2436b51cd..000000000 --- a/Sources/_StringProcessing/Unicode/Data.swift +++ /dev/null @@ -1,188 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - - -internal typealias ScalarAndNormData = ( - scalar: Unicode.Scalar, - normData: Unicode._NormData -) - -extension Unicode { - // A wrapper type over the normalization data value we receive when we - // lookup a scalar's normalization information. The layout of the underlying - // 16 bit value we receive is as follows: - // - // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - // └───┬───┘ └──── CCC ────┘ └─┘ │ - // │ │ └── NFD_QC - // │ └── NFC_QC - // └── Unused - // - // NFD_QC: This is a simple Yes/No on whether the scalar has canonical - // decomposition. Note: Yes is indicated via 0 instead of 1. - // - // NFC_QC: This is either Yes/No/Maybe on whether the scalar is NFC quick - // check. Yes, represented as 0, means the scalar can NEVER compose - // with another scalar previous to it. No, represented as 1, means the - // scalar can NEVER appear within a well formed NFC string. Maybe, - // represented as 2, means the scalar could appear with an NFC string, - // but further information is required to determine if that is the - // case. At the moment, we really only care about Yes/No. - // - // CCC: This is the canonical combining class property of a scalar that is - // used when sorting scalars of a normalization segment after NFD - // computation. A scalar with a CCC value of 128 can NEVER appear before - // a scalar with a CCC value of 100, unless there are normalization - // boundaries between them. - // - internal struct _NormData { - var rawValue: UInt16 - - var ccc: UInt8 { - UInt8(truncatingIfNeeded: rawValue >> 3) - } - - var isNFCQC: Bool { - rawValue & 0x6 == 0 - } - - var isNFDQC: Bool { - rawValue & 0x1 == 0 - } - - init(_ scalar: Unicode.Scalar, fastUpperbound: UInt32 = 0xC0) { - if _fastPath(scalar.value < fastUpperbound) { - // CCC = 0, NFC_QC = Yes, NFD_QC = Yes - rawValue = 0 - } else { - rawValue = _swift_stdlib_getNormData(scalar.value) - - // Because we don't store precomposed hangul in our NFD_QC data, these - // will return true for NFD_QC when in fact they are not. - if (0xAC00 ... 0xD7A3).contains(scalar.value) { - // NFD_QC = false - rawValue |= 0x1 - } - } - } - - init(rawValue: UInt16) { - self.rawValue = rawValue - } - } -} - -extension Unicode { - // A wrapper type for normalization buffers in the NFC and NFD iterators. - // This helps remove some of the buffer logic like removal and sorting out of - // the iterators and into this type. - internal struct _NormDataBuffer { - var storage: [ScalarAndNormData] = [] - - // This is simply a marker denoting that we've built up our storage, and - // now everything within it needs to be emitted. We reverse the buffer and - // pop elements from the back as a way to remove them. - var isReversed = false - - var isEmpty: Bool { - storage.isEmpty - } - - var last: ScalarAndNormData? { - storage.last - } - - mutating func append(_ scalarAndNormData: ScalarAndNormData) { - _internalInvariant(!isReversed) - storage.append(scalarAndNormData) - } - - // Removes the first element from the buffer. Note: it is not safe to append - // to the buffer after this function has been called. We reverse the storage - // internally for everything to be emitted out, so appending would insert - // into the storage at the wrong location. One must continue to call this - // function until a 'nil' return value has been received before appending. - mutating func next() -> ScalarAndNormData? { - guard !storage.isEmpty else { - isReversed = false - return nil - } - - // If our storage hasn't been reversed yet, do so now. - if !isReversed { - storage.reverse() - isReversed = true - } - - return storage.removeLast() - } - - // Sort the entire buffer based on the canonical combining class. - mutating func sort() { - storage._insertionSort(within: storage.indices) { - $0.normData.ccc < $1.normData.ccc - } - } - } -} - -extension Unicode { - // A wrapper type over the decomposition entry value we receive when we - // lookup a scalar's canonical decomposition. The layout of the underlying - // 32 bit value we receive is as follows: - // - // Top 14 bits Bottom 18 bits - // - // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - // └───────── Index ─────────┘ └───────── Hashed Scalar ─────────┘ - // - // Index: This is the direct index into '_swift_stdlib_nfd_decompositions' - // that points to a size byte indicating the overall size of the - // UTF-8 decomposition string. Following the size byte is said string. - // - // Hashed Scalar: Because perfect hashing doesn't know the original set of - // keys it was hashed with, we store the original scalar in the - // decomposition entry so that we can guard against scalars - // who happen to hash to the same index. - // - internal struct _DecompositionEntry { - let rawValue: UInt32 - - // Our original scalar is stored in the first 18 bits of this entry. - var hashedScalar: Unicode.Scalar { - Unicode.Scalar(_value: (rawValue << 14) >> 14) - } - - // The index into the decomposition array is stored in the top 14 bits. - var index: Int { - Int(truncatingIfNeeded: rawValue >> 18) - } - - // A buffer pointer to the UTF8 decomposition string. - var utf8: UnsafeBufferPointer { - let decompPtr = _swift_stdlib_nfd_decompositions()._unsafelyUnwrappedUnchecked - - // This size is the utf8 length of the decomposition. - let size = Int(truncatingIfNeeded: decompPtr[index]) - - return UnsafeBufferPointer( - // We add 1 here to skip the size byte. - start: decompPtr + index + 1, - count: size - ) - } - - init(_ scalar: Unicode.Scalar) { - rawValue = _swift_stdlib_getDecompositionEntry(scalar.value) - } - } -} diff --git a/Sources/_StringProcessing/Unicode/Graphemes.swift b/Sources/_StringProcessing/Unicode/Graphemes.swift deleted file mode 100644 index d2c5f6a0b..000000000 --- a/Sources/_StringProcessing/Unicode/Graphemes.swift +++ /dev/null @@ -1,668 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// -//===----------------------------------------------------------------------===// - -@_silgen_name("_swift_stdlib_isLinkingConsonant") -func _swift_stdlib_isLinkingConsonant(_: UInt32) -> Bool - -@_silgen_name("_swift_stdlib_getGraphemeBreakProperty") -func _swift_stdlib_getGraphemeBreakProperty(_: UInt32) -> UInt8 - -extension Unicode { - internal enum _GraphemeBreakProperty { - case any - case control - case extend - case extendedPictographic - case l - case lv - case lvt - case prepend - case regionalIndicator - case spacingMark - case t - case v - case zwj - - init(from scalar: Unicode.Scalar) { - switch scalar.value { - // Some fast paths for ascii characters... - case 0x0 ... 0x1F: - self = .control - case 0x20 ... 0x7E: - self = .any - - case 0x200D: - self = .zwj - case 0x1100 ... 0x115F, - 0xA960 ... 0xA97C: - self = .l - case 0x1160 ... 0x11A7, - 0xD7B0 ... 0xD7C6: - self = .v - case 0x11A8 ... 0x11FF, - 0xD7CB ... 0xD7FB: - self = .t - case 0xAC00 ... 0xD7A3: - if scalar.value % 28 == 16 { - self = .lv - } else { - self = .lvt - } - case 0x1F1E6 ... 0x1F1FF: - self = .regionalIndicator - case 0x1FC00 ... 0x1FFFD: - self = .extendedPictographic - case 0xE01F0 ... 0xE0FFF: - self = .control - default: - // Otherwise, default to binary searching the data array. - let rawEnumValue = _swift_stdlib_getGraphemeBreakProperty(scalar.value) - - switch rawEnumValue { - case 0: - self = .control - case 1: - self = .extend - case 2: - self = .prepend - case 3: - self = .spacingMark - - // Extended pictographic uses 2 values for its representation. - case 4, 5: - self = .extendedPictographic - default: - self = .any - } - } - } - } -} - -/// CR and LF are common special cases in grapheme breaking logic -private var _CR: UInt8 { return 0x0d } -private var _LF: UInt8 { return 0x0a } - -internal func _hasGraphemeBreakBetween( - _ lhs: Unicode.Scalar, _ rhs: Unicode.Scalar -) -> Bool { - - // CR-LF is a special case: no break between these - if lhs == Unicode.Scalar(_CR) && rhs == Unicode.Scalar(_LF) { - return false - } - - // Whether the given scalar, when it appears paired with another scalar - // satisfying this property, has a grapheme break between it and the other - // scalar. - func hasBreakWhenPaired(_ x: Unicode.Scalar) -> Bool { - // TODO: This doesn't generate optimal code, tune/re-write at a lower - // level. - // - // NOTE: Order of case ranges affects codegen, and thus performance. All - // things being equal, keep existing order below. - switch x.value { - // Unified CJK Han ideographs, common and some supplemental, amongst - // others: - // U+3400 ~ U+A4CF - case 0x3400...0xa4cf: return true - - // Repeat sub-300 check, this is beneficial for common cases of Latin - // characters embedded within non-Latin script (e.g. newlines, spaces, - // proper nouns and/or jargon, punctuation). - // - // NOTE: CR-LF special case has already been checked. - case 0x0000...0x02ff: return true - - // Non-combining kana: - // U+3041 ~ U+3096 - // U+30A1 ~ U+30FC - case 0x3041...0x3096: return true - case 0x30a1...0x30fc: return true - - // Non-combining modern (and some archaic) Cyrillic: - // U+0400 ~ U+0482 (first half of Cyrillic block) - case 0x0400...0x0482: return true - - // Modern Arabic, excluding extenders and prependers: - // U+061D ~ U+064A - case 0x061d...0x064a: return true - - // Precomposed Hangul syllables: - // U+AC00 ~ U+D7AF - case 0xac00...0xd7af: return true - - // Common general use punctuation, excluding extenders: - // U+2010 ~ U+2029 - case 0x2010...0x2029: return true - - // CJK punctuation characters, excluding extenders: - // U+3000 ~ U+3029 - case 0x3000...0x3029: return true - - // Full-width forms: - // U+FF01 ~ U+FF9D - case 0xFF01...0xFF9D: return true - - default: return false - } - } - return hasBreakWhenPaired(lhs) && hasBreakWhenPaired(rhs) -} - -extension Unicode.Scalar { - fileprivate var _isLinkingConsonant: Bool { - _swift_stdlib_isLinkingConsonant(value) - } - - fileprivate var _isVirama: Bool { - switch value { - // Devanagari - case 0x94D: - return true - // Bengali - case 0x9CD: - return true - // Gujarati - case 0xACD: - return true - // Oriya - case 0xB4D: - return true - // Telugu - case 0xC4D: - return true - // Malayalam - case 0xD4D: - return true - - default: - return false - } - } -} - -internal struct _GraphemeBreakingState { - // When we're looking through an indic sequence, one of the requirements is - // that there is at LEAST 1 Virama present between two linking consonants. - // This value helps ensure that when we ultimately need to decide whether or - // not to break that we've at least seen 1 when walking. - var hasSeenVirama = false - - // When walking forwards in a string, we need to know whether or not we've - // entered an emoji sequence to be able to eventually break after all of the - // emoji's various extenders and zero width joiners. This bit allows us to - // keep track of whether or not we're still in an emoji sequence when deciding - // to break. - var isInEmojiSequence = false - - // Similar to emoji sequences, we need to know not to break an Indic grapheme - // sequence. This sequence is (potentially) composed of many scalars and isn't - // as trivial as comparing two grapheme properties. - var isInIndicSequence = false - - // When walking forward in a string, we need to not break on emoji flag - // sequences. Emoji flag sequences are composed of 2 regional indicators, so - // when we see our first (.regionalIndicator, .regionalIndicator) decision, - // we need to know to return false in this case. However, if the next scalar - // is another regional indicator, we reach the same decision rule, but in this - // case we actually need to break there's a boundary between emoji flag - // sequences. - var shouldBreakRI = false -} - -extension String { - // Returns the stride of the next grapheme cluster at the previous boundary - // offset. - internal func nextBoundary( - startingAt index: Int, - nextScalar: (Int) -> (Unicode.Scalar, end: Int) - ) -> Int { - _internalInvariant(index != endIndex._encodedOffset) - var state = _GraphemeBreakingState() - var index = index - - while true { - let (scalar1, nextIdx) = nextScalar(index) - index = nextIdx - - guard index != endIndex._encodedOffset else { - break - } - - let (scalar2, _) = nextScalar(index) - - if shouldBreak(scalar1, between: scalar2, &state, index) { - break - } - } - - return index - } - - // Returns the stride of the previous grapheme cluster at the current boundary - // offset. - internal func previousBoundary( - endingAt index: Int, - previousScalar: (Int) -> (Unicode.Scalar, start: Int) - ) -> Int { - _internalInvariant(index != startIndex._encodedOffset) - var state = _GraphemeBreakingState() - var index = index - - while true { - let (scalar2, previousIdx) = previousScalar(index) - index = previousIdx - - guard index != startIndex._encodedOffset else { - break - } - - let (scalar1, _) = previousScalar(index) - - if shouldBreak( - scalar1, - between: scalar2, - &state, - index, - isBackwards: true - ) { - break - } - } - - return index - } -} - -extension String { - // The "algorithm" that determines whether or not we should break between - // certain grapheme break properties. - // - // This is based off of the Unicode Annex #29 for [Grapheme Cluster Boundary - // Rules](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules). - internal func shouldBreak( - _ scalar1: Unicode.Scalar, - between scalar2: Unicode.Scalar, - _ state: inout _GraphemeBreakingState, - _ index: Int, - isBackwards: Bool = false - ) -> Bool { - // GB3 - if scalar1.value == 0xD, scalar2.value == 0xA { - return false - } - - if _hasGraphemeBreakBetween(scalar1, scalar2) { - return true - } - - let x = Unicode._GraphemeBreakProperty(from: scalar1) - let y = Unicode._GraphemeBreakProperty(from: scalar2) - - // This variable and the defer statement help toggle the isInEmojiSequence - // state variable to false after every decision of 'shouldBreak'. If we - // happen to see a rhs .extend or .zwj, then it's a signal that we should - // continue treating the current grapheme cluster as an emoji sequence. - var enterEmojiSequence = false - - // Very similar to emoji sequences, but for Indic grapheme sequences. - var enterIndicSequence = false - - defer { - state.isInEmojiSequence = enterEmojiSequence - state.isInIndicSequence = enterIndicSequence - } - - switch (x, y) { - - // Fast path: If we know our scalars have no properties the decision is - // trivial and we don't need to crawl to the default statement. - case (.any, .any): - return true - - // GB4 - case (.control, _): - return true - - // GB5 - case (_, .control): - return true - - // GB6 - case (.l, .l), - (.l, .v), - (.l, .lv), - (.l, .lvt): - return false - - // GB7 - case (.lv, .v), - (.v, .v), - (.lv, .t), - (.v, .t): - return false - - // GB8 - case (.lvt, .t), - (.t, .t): - return false - - // GB9 (partial GB11) - case (_, .extend), - (_, .zwj): - - // If we're currently in an emoji sequence, then extends and ZWJ help - // continue the grapheme cluster by combining more scalars later. If we're - // not currently in an emoji sequence, but our lhs scalar is a pictograph, - // then that's a signal that it's the start of an emoji sequence. - if state.isInEmojiSequence || x == .extendedPictographic { - enterEmojiSequence = true - } - - // If we're currently in an indic sequence (or if our lhs is a linking - // consonant), then this check and everything underneath ensures that - // we continue being in one and may check if this extend is a Virama. - if state.isInIndicSequence || scalar1._isLinkingConsonant { - if y == .extend { - let extendNormData = Unicode._NormData(scalar2, fastUpperbound: 0x300) - - // If our extend's CCC is 0, then this rule does not apply. - guard extendNormData.ccc != 0 else { - return false - } - } - - enterIndicSequence = true - - if scalar2._isVirama { - state.hasSeenVirama = true - } - } - - return false - - // GB9a - case (_, .spacingMark): - return false - - // GB9b - case (.prepend, _): - return false - - // GB11 - case (.zwj, .extendedPictographic): - if isBackwards { - return !checkIfInEmojiSequence(index) - } - - return !state.isInEmojiSequence - - // GB12 & GB13 - case (.regionalIndicator, .regionalIndicator): - if isBackwards { - return countRIs(index) - } - - defer { - state.shouldBreakRI.toggle() - } - - return state.shouldBreakRI - - // GB999 - default: - // GB9c - if state.isInIndicSequence, state.hasSeenVirama, scalar2._isLinkingConsonant { - state.hasSeenVirama = false - return false - } - - // Handle GB9c when walking backwards. - if isBackwards { - switch (x, scalar2._isLinkingConsonant) { - case (.extend, true): - let extendNormData = Unicode._NormData(scalar1, fastUpperbound: 0x300) - - guard extendNormData.ccc != 0 else { - return true - } - - return !checkIfInIndicSequence(index) - - case (.zwj, true): - return !checkIfInIndicSequence(index) - - default: - return true - } - } - - return true - } - } - - // When walking backwards, it's impossible to know whether we were in an emoji - // sequence without walking further backwards. This walks the string backwards - // enough until we figure out whether or not to break our - // (.zwj, .extendedPictographic) question. For example: - // - // Scalar view #1: - // - // [.control, .zwj, .extendedPictographic] - // ^ - // | = To determine whether or not we break here, we need - // to see the previous scalar's grapheme property. - // ^ - // | = This is neither .extendedPictographic nor .extend, thus we - // were never in an emoji sequence, so break between the .zwj - // and .extendedPictographic. - // - // Scalar view #2: - // - // [.extendedPictographic, .zwj, .extendedPictographic] - // ^ - // | = Same as above, move backwards one to - // view the previous scalar's property. - // ^ - // | = This is an .extendedPictographic, so this indicates that - // we are in an emoji sequence, so we should NOT break - // between the .zwj and .extendedPictographic. - // - // Scalar view #3: - // - // [.extendedPictographic, .extend, .extend, .zwj, .extendedPictographic] - // ^ - // | = Same as above - // ^ - // | = This is an .extend which means - // there is a potential emoji - // sequence, walk further backwards - // to find an .extendedPictographic. - // - // <-- = Another extend, go backwards more. - // ^ - // | = We found our starting .extendedPictographic letting us - // know that we are in an emoji sequence so our initial - // break question is answered as NO. - internal func checkIfInEmojiSequence(_ index: Int) -> Bool { - var emojiIdx = String.Index(_encodedOffset: index) - - guard emojiIdx != startIndex else { - return false - } - - let scalars = unicodeScalars - scalars.formIndex(before: &emojiIdx) - - while emojiIdx != startIndex { - scalars.formIndex(before: &emojiIdx) - let scalar = scalars[emojiIdx] - - let gbp = Unicode._GraphemeBreakProperty(from: scalar) - - switch gbp { - case .extend: - continue - case .extendedPictographic: - return true - default: - return false - } - } - - return false - } - - // When walking backwards, it's impossible to know whether we break when we - // see our first ((.extend|.zwj), .linkingConsonant) without walking - // further backwards. This walks the string backwards enough until we figure - // out whether or not to break this indic sequence. For example: - // - // Scalar view #1: - // - // [.virama, .extend, .linkingConsonant] - // ^ - // | = To be able to know whether or not to break these - // two, we need to walk backwards to determine if - // this is a legitimate indic sequence. - // ^ - // | = The scalar sequence ends without a starting linking consonant, - // so this is in fact not an indic sequence, so we can break the two. - // - // Scalar view #2: - // - // [.linkingConsonant, .virama, .extend, .linkingConsonant] - // ^ - // | = Same as above - // ^ - // | = This is a virama, so we at least have seen - // 1 to be able to return true if we see a - // linking consonant later. - // ^ - // | = Is a linking consonant and we've seen a virama, so this is a - // legitimate indic sequence, so do NOT break the initial question. - internal func checkIfInIndicSequence(_ index: Int) -> Bool { - var indicIdx = String.Index(_encodedOffset: index) - - guard indicIdx != startIndex else { - return false - } - - let scalars = unicodeScalars - scalars.formIndex(before: &indicIdx) - - var hasSeenVirama = false - - // Check if the first extend was the Virama. - let scalar = scalars[indicIdx] - - if scalar._isVirama { - hasSeenVirama = true - } - - while indicIdx != startIndex { - scalars.formIndex(before: &indicIdx) - let scalar = scalars[indicIdx] - - let gbp = Unicode._GraphemeBreakProperty(from: scalar) - - switch (gbp, scalar._isLinkingConsonant) { - case (.extend, false): - let extendNormData = Unicode._NormData(scalar, fastUpperbound: 0x300) - - guard extendNormData.ccc != 0 else { - return false - } - - if scalar._isVirama { - hasSeenVirama = true - } - - case (.zwj, false): - continue - - // LinkingConsonant - case (_, true): - guard hasSeenVirama else { - return false - } - - return true - - default: - return false - } - } - - return false - } - - // When walking backwards, it's impossible to know whether we break when we - // see our first (.regionalIndicator, .regionalIndicator) without walking - // further backwards. This walks the string backwards enough until we figure - // out whether or not to break these RIs. For example: - // - // Scalar view #1: - // - // [.control, .regionalIndicator, .regionalIndicator] - // ^ - // | = To be able to know whether or not to - // break these two, we need to walk - // backwards to determine if there were - // any previous .regionalIndicators in - // a row. - // ^ - // | = Not a .regionalIndicator, so our total riCount is 0 and 0 is - // even thus we do not break. - // - // Scalar view #2: - // - // [.control, .regionalIndicator, .regionalIndicator, .regionalIndicator] - // ^ - // | = Same as above - // ^ - // | = This is a .regionalIndicator, so continue - // walking backwards for more of them. riCount is - // now equal to 1. - // ^ - // | = Not a .regionalIndicator. riCount = 1 which is odd, so break - // the last two .regionalIndicators. - internal func countRIs( - _ index: Int - ) -> Bool { - var riIdx = String.Index(_encodedOffset: index) - - guard riIdx != startIndex else { - return false - } - - var riCount = 0 - - let scalars = unicodeScalars - scalars.formIndex(before: &riIdx) - - while riIdx != startIndex { - scalars.formIndex(before: &riIdx) - let scalar = scalars[riIdx] - - let gbp = Unicode._GraphemeBreakProperty(from: scalar) - - guard gbp == .regionalIndicator else { - break - } - - riCount += 1 - } - - return riCount & 1 != 0 - } -} diff --git a/Sources/_StringProcessing/Unicode/Normalization.swift b/Sources/_StringProcessing/Unicode/Normalization.swift deleted file mode 100644 index ce73aac47..000000000 --- a/Sources/_StringProcessing/Unicode/Normalization.swift +++ /dev/null @@ -1,406 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// -//===----------------------------------------------------------------------===// - -@_silgen_name("_swift_stdlib_getNormData") -func _swift_stdlib_getNormData(_: UInt32) -> UInt16 - -@_silgen_name("_swift_stdlib_nfd_decompositions") -func _swift_stdlib_nfd_decompositions() -> UnsafePointer? - -@_silgen_name("_swift_stdlib_getDecompositionEntry") -func _swift_stdlib_getDecompositionEntry(_: UInt32) -> UInt32 - -@_silgen_name("_swift_stdlib_getComposition") -func _swift_stdlib_getComposition(_: UInt32, _: UInt32) -> UInt32 - -extension Unicode { - internal struct _NFD { - let base: S - } -} - -extension Unicode._NFD { - internal struct Iterator { - var buffer = Unicode._NormDataBuffer() - - // This index always points at the next starter of a normalization segment. - // Each iteration of 'next()' moves this index up to the next starter. - var index: S.UnicodeScalarView.Index - - let unicodeScalars: S.UnicodeScalarView - } -} - -extension Unicode._NFD.Iterator: IteratorProtocol { - internal mutating func decompose( - _ scalar: Unicode.Scalar, - with normData: Unicode._NormData - ) { - // ASCII always decomposes to itself. - if _fastPath(scalar.value < 0xC0) { - // ASCII always has normData of 0. - // CCC = 0, NFC_QC = Yes, NFD_QC = Yes - buffer.append((scalar, normData)) - return - } - - // Handle Hangul decomposition algorithmically. - // S.base = 0xAC00 - // S.count = 11172 - // S.base + S.count - 1 = 0xD7A3 - if (0xAC00 ... 0xD7A3).contains(scalar.value) { - decomposeHangul(scalar) - return - } - - // Otherwise, we need to lookup the decomposition (if there is one). - decomposeSlow(scalar, with: normData) - } - - @inline(never) - internal mutating func decomposeHangul(_ scalar: Unicode.Scalar) { - // L = Hangul leading consonants - let L: (base: UInt32, count: UInt32) = (base: 0x1100, count: 19) - // V = Hangul vowels - let V: (base: UInt32, count: UInt32) = (base: 0x1161, count: 21) - // T = Hangul tail consonants - let T: (base: UInt32, count: UInt32) = (base: 0x11A7, count: 28) - // N = Number of precomposed Hangul syllables that start with the same - // leading consonant. (There is no base for N). - let N: (base: UInt32, count: UInt32) = (base: 0x0, count: 588) - // S = Hangul precomposed syllables - let S: (base: UInt32, count: UInt32) = (base: 0xAC00, count: 11172) - - let sIdx = scalar.value &- S.base - - let lIdx = sIdx / N.count - let l = Unicode.Scalar(_value: L.base &+ lIdx) - // Hangul leading consonants, L, always have normData of 0. - // CCC = 0, NFC_QC = Yes, NFD_QC = Yes - buffer.append((scalar: l, normData: .init(rawValue: 0))) - - let vIdx = (sIdx % N.count) / T.count - let v = Unicode.Scalar(_value: V.base &+ vIdx) - // Hangul vowels, V, always have normData of 4. - // CCC = 0, NFC_QC = Maybe, NFD_QC = Yes - buffer.append((scalar: v, normData: .init(rawValue: 4))) - - let tIdx = sIdx % T.count - if tIdx != 0 { - let t = Unicode.Scalar(_value: T.base &+ tIdx) - // Hangul tail consonants, T, always have normData of 4. - // CCC = 0, NFC_QC = Maybe, NFD_QC = Yes - buffer.append((scalar: t, normData: .init(rawValue: 4))) - } - } - - @inline(never) - internal mutating func decomposeSlow( - _ scalar: Unicode.Scalar, - with normData: Unicode._NormData - ) { - // Look into the decomposition perfect hash table. - let decompEntry = Unicode._DecompositionEntry(scalar) - - // If this is not our original scalar, then we have no decomposition for this - // scalar, so just emit itself. This is required because perfect hashing - // does not know the original set of keys that it used to create itself, so - // we store the original scalar in our decomposition entry to ensure that - // scalars that hash to the same index don't succeed. - guard scalar == decompEntry.hashedScalar else { - buffer.append((scalar, normData)) - return - } - - var utf8 = decompEntry.utf8 - - while utf8.count > 0 { - let (scalar, len) = UnsafeAssumingValidUTF8.decode( - utf8.byteBuffer, - startingAt: 0 - ) - utf8 = UnsafeBufferPointer(rebasing: utf8[len...]) - - // Fast path: Because this will be emitted into the completed NFD buffer, - // we don't need to look at NFD_QC anymore which lets us do a larger - // latiny check for NFC_QC and CCC (0xC0 vs. 0x300). - let normData = Unicode._NormData(scalar, fastUpperbound: 0x300) - - buffer.append((scalar, normData)) - } - } - - internal mutating func next() -> ScalarAndNormData? { - // Empty out our buffer before attempting to decompose the next - // normalization segment. - if let nextBuffered = buffer.next() { - return nextBuffered - } - - while index < unicodeScalars.endIndex { - let scalar = unicodeScalars[index] - let normData = Unicode._NormData(scalar) - - // If we've reached a starter, stop. - if normData.ccc == 0, !buffer.isEmpty { - break - } - - unicodeScalars.formIndex(after: &index) - - // If our scalar IS NFD quick check, then it's as simple as appending to - // our buffer and moving on the next scalar. Otherwise, we need to - // decompose this and append each decomposed scalar. - if normData.isNFDQC { - // Fast path: If our scalar is also ccc = 0, then this doesn't need to - // be appended to the buffer at all. - if normData.ccc == 0 { - return (scalar, normData) - } - - buffer.append((scalar, normData)) - } else { - decompose(scalar, with: normData) - } - } - - // Sort the entire buffer based on the canonical combining class. - buffer.sort() - - return buffer.next() - } -} - -extension Unicode._NFD: Sequence { - internal func makeIterator() -> Iterator { - Iterator( - index: base.unicodeScalars.startIndex, - unicodeScalars: base.unicodeScalars - ) - } -} - -extension StringProtocol { - internal var _nfd: Unicode._NFD { - Unicode._NFD(base: self) - } -} - -extension Unicode { - internal struct _NFC { - let base: S - } -} - -extension Unicode._NFC { - internal struct Iterator { - var buffer = Unicode._NormDataBuffer() - - // This is our starter that is currently being composed with other scalars - // into new scalars. For example, "e\u{301}", here our first scalar is 'e', - // which is a starter, thus we assign composee to this 'e' and move to the - // next scalar. We attempt to compose our composee, 'e', with '\u{301}' and - // find that there is a composition. Thus our new composee is now 'é' and - // we continue to try and compose following scalars with this composee. - var composee: Unicode.Scalar? = nil - - var iterator: Unicode._NFD.Iterator - } -} - -extension Unicode._NFC.Iterator: IteratorProtocol { - internal func compose( - _ x: Unicode.Scalar, - and y: Unicode.Scalar - ) -> Unicode.Scalar? { - // Fast path: ASCII and some latiny scalars never compose when they're on - // the rhs. - if _fastPath(y.value < 0x300) { - return nil - } - - if let hangul = composeHangul(x, and: y) { - return hangul - } - - // Otherwise, lookup the composition. - let composition = _swift_stdlib_getComposition(x.value, y.value) - - guard composition != .max else { - return nil - } - - return Unicode.Scalar(_value: composition) - } - - @inline(never) - internal func composeHangul( - _ x: Unicode.Scalar, - and y: Unicode.Scalar - ) -> Unicode.Scalar? { - // L = Hangul leading consonants - let L: (base: UInt32, count: UInt32) = (base: 0x1100, count: 19) - // V = Hangul vowels - let V: (base: UInt32, count: UInt32) = (base: 0x1161, count: 21) - // T = Hangul tail consonants - let T: (base: UInt32, count: UInt32) = (base: 0x11A7, count: 28) - // N = Number of precomposed Hangul syllables that start with the same - // leading consonant. (There is no base for N). - let N: (base: UInt32, count: UInt32) = (base: 0x0, count: 588) - // S = Hangul precomposed syllables - let S: (base: UInt32, count: UInt32) = (base: 0xAC00, count: 11172) - - switch (x.value, y.value) { - // Check for Hangul (L, V) -> LV compositions. - case (L.base ..< L.base &+ L.count, V.base ..< V.base &+ V.count): - let lIdx = x.value &- L.base - let vIdx = y.value &- V.base - let lvIdx = lIdx &* N.count &+ vIdx &* T.count - let s = S.base &+ lvIdx - return Unicode.Scalar(_value: s) - - // Check for Hangul (LV, T) -> LVT compositions. - case (S.base ..< S.base &+ S.count, T.base &+ 1 ..< T.base &+ T.count): - if (x.value &- S.base) % T.count == 0 { - return Unicode.Scalar(_value: x.value &+ y.value &- T.base) - } else { - fallthrough - } - - default: - return nil - } - } - - internal mutating func next() -> Unicode.Scalar? { - // Empty out our buffer before attempting to compose anything with our new - // composee. - if let nextBuffered = buffer.next() { - return nextBuffered.scalar - } - - while let current = iterator.next() { - guard let currentComposee = composee else { - // If we don't have a composee at this point, we're most likely looking - // at the start of a string. If our class is 0, then attempt to compose - // the following scalars with this one. Otherwise, it's a one off scalar - // that needs to be emitted. - if current.normData.ccc == 0 { - composee = current.scalar - continue - } else { - return current.scalar - } - } - - // If we have any scalars in the buffer, it means those scalars couldn't - // compose with our composee to form a new scalar. However, scalars - // following them may still compose with our composee, so take the last - // scalar in the buffer and get its normalization data so that we can - // perform the check underneath this one about whether this current scalar - // is "blocked". We get the last scalar because the scalars we receive are - // already NFD, so the last scalar in the buffer will have the highest - // CCC value in this normalization segment. - guard let lastBufferedNormData = buffer.last?.normData else { - // If we do not any have scalars in our buffer yet, then this step is - // trivial. Attempt to compose our current scalar with whatever composee - // we're currently building up. - - // If our right hand side scalar IS NFC_QC, then that means it can - // never compose with any scalars previous to it. So, if our current - // scalar is NFC_QC, then we have no composition. - guard !current.normData.isNFCQC, - let composed = compose(currentComposee, and: current.scalar) else { - // We did not find a composition between the two. If our current class - // is 0, then set that as the new composee and return whatever built - // up scalar we have. Otherwise, add our current scalar to the buffer - // for eventual removal! - - if current.normData.ccc == 0 { - composee = current.scalar - return currentComposee - } - - buffer.append(current) - continue - } - - // We found a composition! Record it as our new composee and repeat the - // process. - composee = composed - continue - } - - // Check if our current scalar is not blocked from our current composee. - // In this case blocked means there is some scalar whose class - // (lastBufferedNormData.ccc) is either == 0 or >= current.normData.ccc. - // - // Example: - // - // "z\u{0335}\u{0327}\u{0324}\u{0301}" - // - // In this example, there are several combining marks following a 'z', but - // none of them actually compose with the composee 'z'. However, the last - // scalar U+0301 does actually compose. So this check makes sure that the - // last scalar doesn't have any scalar in between it and the composee that - // would otherwise "block" it from composing. - guard lastBufferedNormData.ccc < current.normData.ccc else { - // We had a scalar block it. That means our current scalar is either a - // starter or has a same class (preserve ordering). - - // Starters are the "start" of a new normalization segment. Set it as - // the new composee and return our current composee. This will trigger - // any other scalars in the buffer to be emitted before we handle - // normalizing this new segment. - if current.normData.ccc == 0 { - composee = current.scalar - return currentComposee - } - - _internalInvariant(current.normData.ccc == lastBufferedNormData.ccc) - buffer.append(current) - continue - } - - // There were no blockers! Attempt to compose the two! (Again, if our rhs - // scalar IS NFC_QC, then it can never compose with anything previous to - // it). - guard !current.normData.isNFCQC, - let composed = compose(currentComposee, and: current.scalar) else { - // No composition found. Stick it at the end of the buffer with the rest - // of non-composed scalars. - - buffer.append(current) - continue - } - - // They composed! Assign the composition as our new composee and iterate - // to the next scalar. - composee = composed - } - - // If we have a leftover composee, make sure to return it. - return composee._take() - } -} - -extension Unicode._NFC: Sequence { - internal func makeIterator() -> Iterator { - Iterator(iterator: base._nfd.makeIterator()) - } -} - -extension StringProtocol { - internal var _nfc: Unicode._NFC { - Unicode._NFC(base: self) - } -} - From addfbfdd9b26fde35e2e708959bd5562342c5658 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Fri, 1 Apr 2022 22:45:35 +0100 Subject: [PATCH 027/133] Update pitch --- Documentation/Evolution/DelimiterSyntax.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index e06789a57..e1376ca7d 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -80,7 +80,7 @@ func matchHexAssignment(_ input: String) -> (String, Int)? { } ``` -Unnamed capture groups produce unlabeled tuple elements and must be referenced by their position, e.g `match.1`, `match.2`. +Unnamed capture groups produce unlabeled tuple elements and must be referenced by their position, e.g `match.1`, `match.2`. See [StronglyTypedCaptures.md](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/StronglyTypedCaptures.md) for more info. **TODO: Should we cover more general typed capture behavior from [StronglyTypedCaptures.md](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/StronglyTypedCaptures.md) here? There is some overlap with the typed capture behavior of the DSL tho, labels are the main thing that are literal specific** @@ -156,7 +156,7 @@ Perhaps the most obvious parsing ambiguity with `/.../` delimiters is with comme ### Ambiguity with infix operators -There would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required `x + /y/` for regex literal interpretation. Alternatively, extended syntax may be used, e.g `x+#/y/#`. +There would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required for regex literal interpretation, e.g `x + /y/`. Alternatively, extended syntax may be used, e.g `x+#/y/#`. ### Regex syntax limitations @@ -241,8 +241,6 @@ Postfix `/` operators do not require banning, as they'd only be treated as regex #### `/,` and `/]` as regex literal openings -**TODO: Do we still want to break source here given we're also proposing `#/.../#`?** - As stated previously, there is a parsing ambiguity with unapplied operators in argument lists, tuples, and parentheses. Some of these cases can be mitigated by not parsing a regex literal if the starting character is `)`. However it does not solve the issue when the next character is `,` or `]`. Both of these are valid regex starting characters, and comma in particular may be a fairly common case for a regex. For example: @@ -284,7 +282,9 @@ This takes advantage of the fact that a regex literal will not be parsed if the ## Future Directions -**TODO: Do we have any other future directions now that extended multi-line syntax has been subsumed?** +### Modern literal syntax + +We could support a more modern Swift-like syntax in regex literals. For example, comments could be done with `//` and `/* ... */`, and quoted sequences could be done with `"..."`. This would however be incompatible with the syntactic superset of regex syntax we intend to parse, and as such may need to be introduced using a new literal kind, with no obvious choice of delimiter. However, it's possible that the ability to use regex literals in the DSL lessens the benefit that this syntax would bring. ## Alternatives Considered From bb819f6f2657bbd425a5816b7a4971067e0052ea Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Fri, 1 Apr 2022 23:13:55 +0100 Subject: [PATCH 028/133] Clarify upgrade path --- Documentation/Evolution/DelimiterSyntax.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index e1376ca7d..0a86e170e 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -29,7 +29,7 @@ The ability to compile regex patterns at run time is useful for cases where it i ## Proposed solution -We propose introducing a new kind of literal for a regex. In a new language mode, a regex literal may be written using `/.../` delimiters: +A regex literal may be written using `/.../` delimiters: ```swift // Matches " = ", extracting the identifier and hex number @@ -39,7 +39,7 @@ let regex = /(?[[:alpha:]]\w*) = (?[0-9A-F]+)/ Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternatives). Their ubiquity and familiarity makes them a compelling choice for Swift. -A regex literal may also be spelled using an extended syntax `#/.../#`, which allows the placement of an arbitrary number of balanced `#` characters around a regex literal. This syntax allows regex literals to contain unescaped forward slashes, and may be used without needing to upgrade to a new language mode. This syntax further allows a multi-line mode when the opening delimiter is followed by a new line. +A regex literal may also be spelled using an extended syntax `#/.../#`, which allows the placement of an arbitrary number of balanced `#` characters around the literal. This syntax may be used to avoid needing to escape forward slashes within the regex. Additionally, it allows for a multi-line mode when the opening delimiter is followed by a new line. Within a regex literal, the compiler will parse the regex syntax outlined in in [the Regex Syntax pitch][internal-syntax], and diagnose any errors at compile time. The capture types and labels are automatically inferred based on the capture groups present in the regex. Using a literal allows editors to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see [Regex builder DSL][regex-dsl]). @@ -63,6 +63,10 @@ Due to the existing use of `/` in comment syntax and operators, there are some s ## Detailed design +### Upgrade path + +Due to the source breaking changes needed for the `/.../` syntax, it will be introduced in Swift 6 mode. However, projects will be able to adopt it earlier by using the compiler flag `-enable-regex-literals`. Note this does not affect the extended syntax `#/.../#`, which will be usable immediately. + ### Typed captures Regex literals have their capture types statically determined by the capture groups present. A initial `Substring` is always present for the entire match, and each capture group adds an additional capture to the match tuple, with named capture groups receiving a corresponding tuple label. Once matched, such captures may later be referenced: @@ -93,7 +97,7 @@ let regex = #/usr/lib/modules/([^/]+)/vmlinuz/# // regex: Regex<(Substring, Substring)> ``` -Additionally, this syntax provides a way to write a regex literal without needing to upgrade to a new language mode. +Additionally, it allows for a multi-line mode when the opening delimiter is followed by a new line. #### Escaping of backslashes @@ -215,7 +219,7 @@ It should be noted that this only mitigates the issue, as it does not handle the ### Language changes required -In addition to ambiguities listed above, there are also some parsing ambiguities that would require the following language changes in a new language mode: +In addition to ambiguities listed above, there are also some parsing ambiguities that require the following language changes in a new language mode: - Deprecation of prefix operators containing the `/` character. - Parsing `/,` and `/]` as the start of a regex literal if a closing `/` is found, rather than an unapplied operator in an argument list. For example, `fn(/, /)` becomes a regex literal rather than 2 unapplied operator arguments. From 36f7160ba6adc86cb049127c26dd182172232fff Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 4 Apr 2022 12:33:25 +0100 Subject: [PATCH 029/133] Remove AST CustomCharacterClass consumer generation This isn't actually used, as we convert to a DSL custom character class, and then use that consumer logic. --- .../_StringProcessing/ConsumerInterface.swift | 118 ------------------ 1 file changed, 118 deletions(-) diff --git a/Sources/_StringProcessing/ConsumerInterface.swift b/Sources/_StringProcessing/ConsumerInterface.swift index 0a2d93ff1..e372280f2 100644 --- a/Sources/_StringProcessing/ConsumerInterface.swift +++ b/Sources/_StringProcessing/ConsumerInterface.swift @@ -295,101 +295,6 @@ extension DSLTree.CustomCharacterClass.Member { } } -extension AST.CustomCharacterClass.Member { - func generateConsumer( - _ opts: MatchingOptions - ) throws -> MEProgram.ConsumeFunction { - switch self { - case .custom(let ccc): - return try ccc.generateConsumer(opts) - - case .range(let r): - guard let lhs = r.lhs.literalCharacterValue else { - throw Unsupported("\(r.lhs) in range") - } - guard let rhs = r.rhs.literalCharacterValue else { - throw Unsupported("\(r.rhs) in range") - } - - return { input, bounds in - // TODO: check for out of bounds? - let curIdx = bounds.lowerBound - if (lhs...rhs).contains(input[curIdx]) { - // TODO: semantic level - return input.index(after: curIdx) - } - return nil - } - - case .atom(let atom): - guard let gen = try atom.generateConsumer(opts) else { - throw Unsupported("TODO") - } - return gen - - case .quote(let q): - // TODO: Not optimal. - let consumers = try q.literal.map { - try AST.Atom(.char($0), .fake).generateConsumer(opts)! - } - return { input, bounds in - for consumer in consumers { - if let idx = consumer(input, bounds) { - return idx - } - } - return nil - } - - case .trivia: - throw Unreachable( - "Should have been stripped by caller") - - case .setOperation(let lhs, let op, let rhs): - // TODO: We should probably have a component type - // instead of a members array... for now we reconstruct - // an AST node... - let start = AST.Located( - faking: AST.CustomCharacterClass.Start.normal) - - let lhs = try AST.CustomCharacterClass( - start, lhs, .fake - ).generateConsumer(opts) - let rhs = try AST.CustomCharacterClass( - start, rhs, .fake - ).generateConsumer(opts) - - return { input, bounds in - // NOTE: Easy way to implement, not performant - let lhsIdxOpt = lhs(input, bounds) - let rhsIdxOpt = rhs(input, bounds) - - // TODO: What if lengths don't line up? - assert(lhsIdxOpt == rhsIdxOpt || lhsIdxOpt == nil - || rhsIdxOpt == nil) - - switch op.value { - case .subtraction: - guard rhsIdxOpt == nil else { return nil } - return lhsIdxOpt - - case .intersection: - if let idx = lhsIdxOpt { - return rhsIdxOpt == nil ? nil : idx - } - return nil - - case .symmetricDifference: - if let idx = lhsIdxOpt { - return rhsIdxOpt == nil ? idx : nil - } - return rhsIdxOpt - } - } - } - } -} - extension DSLTree.CustomCharacterClass { func generateConsumer( _ opts: MatchingOptions @@ -413,29 +318,6 @@ extension DSLTree.CustomCharacterClass { } } -extension AST.CustomCharacterClass { - func generateConsumer( - _ opts: MatchingOptions - ) throws -> MEProgram.ConsumeFunction { - // NOTE: Easy way to implement, obviously not performant - let consumers = try strippingTriviaShallow.members.map { - try $0.generateConsumer(opts) - } - return { input, bounds in - for consumer in consumers { - if let idx = consumer(input, bounds) { - return isInverted ? nil : idx - } - } - if isInverted { - // FIXME: semantic level - return input.index(after: bounds.lowerBound) - } - return nil - } - } -} - // NOTE: Conveniences, though not most performant private func consumeScalarScript( _ s: Unicode.Script From ed9f72c50c5c569cf23384f5766da15f51bc45b8 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 4 Apr 2022 12:33:26 +0100 Subject: [PATCH 030/133] Convert scalar escape sequences to DSL scalars Convert AST escape sequences that represent a scalar value (e.g `\f`, `n`, `\a`) into scalars in the DSL tree. This allows the matching engine to match against them. --- Sources/_RegexParser/Regex/AST/Atom.swift | 64 +++++++++++-------- .../Regex/ASTConversion.swift | 3 + Tests/RegexTests/MatchTests.swift | 23 ++++--- 3 files changed, 53 insertions(+), 37 deletions(-) diff --git a/Sources/_RegexParser/Regex/AST/Atom.swift b/Sources/_RegexParser/Regex/AST/Atom.swift index 0aa0951c5..6482c4042 100644 --- a/Sources/_RegexParser/Regex/AST/Atom.swift +++ b/Sources/_RegexParser/Regex/AST/Atom.swift @@ -631,6 +631,41 @@ extension AST.Atom { } } +extension AST.Atom.EscapedBuiltin { + /// If the escape sequence represents a unicode scalar value, returns the + /// value, otherwise `nil`. + public var scalarValue: UnicodeScalar? { + switch self { + // TODO: Should we separate these into a separate enum? Or move the + // specifics of the scalar to the DSL tree? + case .alarm: + return "\u{7}" + case .backspace: + return "\u{8}" + case .escape: + return "\u{1B}" + case .formfeed: + return "\u{C}" + case .newline: + return "\n" + case .carriageReturn: + return "\r" + case .tab: + return "\t" + + case .singleDataUnit, .decimalDigit, .notDecimalDigit, + .horizontalWhitespace, .notHorizontalWhitespace, .notNewline, + .newlineSequence, .whitespace, .notWhitespace, .verticalTab, + .notVerticalTab, .wordCharacter, .notWordCharacter, .graphemeCluster, + .wordBoundary, .notWordBoundary, .startOfSubject, + .endOfSubjectBeforeNewline, .endOfSubject, + .firstMatchingPositionInSubject, .resetStartOfMatch, .trueAnychar, + .textSegment, .notTextSegment: + return nil + } + } +} + extension AST.Atom { /// Retrieve the character value of the atom if it represents a literal /// character or unicode scalar, nil otherwise. @@ -642,34 +677,7 @@ extension AST.Atom { return Character(s) case .escaped(let c): - switch c { - // TODO: Should we separate these into a separate enum? Or move the - // specifics of the scalar to the DSL tree? - case .alarm: - return "\u{7}" - case .backspace: - return "\u{8}" - case .escape: - return "\u{1B}" - case .formfeed: - return "\u{C}" - case .newline: - return "\n" - case .carriageReturn: - return "\r" - case .tab: - return "\t" - - case .singleDataUnit, .decimalDigit, .notDecimalDigit, - .horizontalWhitespace, .notHorizontalWhitespace, .notNewline, - .newlineSequence, .whitespace, .notWhitespace, .verticalTab, - .notVerticalTab, .wordCharacter, .notWordCharacter, .graphemeCluster, - .wordBoundary, .notWordBoundary, .startOfSubject, - .endOfSubjectBeforeNewline, .endOfSubject, - .firstMatchingPositionInSubject, .resetStartOfMatch, .trueAnychar, - .textSegment, .notTextSegment: - return nil - } + return c.scalarValue.map(Character.init) case .keyboardControl, .keyboardMeta, .keyboardMetaControl: // TODO: These should have unicode scalar values. diff --git a/Sources/_StringProcessing/Regex/ASTConversion.swift b/Sources/_StringProcessing/Regex/ASTConversion.swift index 5336a1892..f773bd275 100644 --- a/Sources/_StringProcessing/Regex/ASTConversion.swift +++ b/Sources/_StringProcessing/Regex/ASTConversion.swift @@ -211,6 +211,9 @@ extension AST.Atom { case .any: return .any case let .backreference(r): return .backreference(r) + case .escaped(let c) where c.scalarValue != nil: + return .scalar(c.scalarValue!) + default: return .unconverted(self) } } diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index 67412d262..0ecbd5ad3 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -281,6 +281,15 @@ extension RegexTests { // code point sequence firstMatchTest(#"\u{61 62 63}"#, input: "123abcxyz", match: "abc", xfail: true) + // Escape sequences that represent scalar values. + firstMatchTest(#"\a[\b]\e\f\n\r\t"#, + input: "\u{7}\u{8}\u{1B}\u{C}\n\r\t", + match: "\u{7}\u{8}\u{1B}\u{C}\n\r\t") + firstMatchTest(#"[\a][\b][\e][\f][\n][\r][\t]"#, + input: "\u{7}\u{8}\u{1B}\u{C}\n\r\t", + match: "\u{7}\u{8}\u{1B}\u{C}\n\r\t") + + firstMatchTest(#"\r\n"#, input: "\r\n", match: "\r\n") // MARK: Quotes @@ -596,24 +605,20 @@ extension RegexTests { func scalar(_ u: UnicodeScalar) -> UInt32 { u.value } - // Currently not supported in the matching engine. for s in scalar("\u{C}") ... scalar("\u{1B}") { let u = UnicodeScalar(s)! - firstMatchTest(#"[\f-\e]"#, input: "\u{B}\u{1C}\(u)", match: "\(u)", - xfail: true) + firstMatchTest(#"[\f-\e]"#, input: "\u{B}\u{1C}\(u)", match: "\(u)") } for u: UnicodeScalar in ["\u{7}", "\u{8}"] { - firstMatchTest(#"[\a-\b]"#, input: "\u{6}\u{9}\(u)", match: "\(u)", - xfail: true) + firstMatchTest(#"[\a-\b]"#, input: "\u{6}\u{9}\(u)", match: "\(u)") } for s in scalar("\u{A}") ... scalar("\u{D}") { let u = UnicodeScalar(s)! - firstMatchTest(#"[\n-\r]"#, input: "\u{9}\u{E}\(u)", match: "\(u)", - xfail: true) + firstMatchTest(#"[\n-\r]"#, input: "\u{9}\u{E}\(u)", match: "\(u)") } - firstMatchTest(#"[\t-\t]"#, input: "\u{8}\u{A}\u{9}", match: "\u{9}", - xfail: true) + firstMatchTest(#"[\t-\t]"#, input: "\u{8}\u{A}\u{9}", match: "\u{9}") + // Currently not supported in the matching engine. for c: UnicodeScalar in ["a", "b", "c"] { firstMatchTest(#"[\c!-\C-#]"#, input: "def\(c)", match: "\(c)", xfail: true) From afcc40b6c1aab7007ff147a6cb4ba127b0542dd2 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Mon, 4 Apr 2022 17:33:01 -0600 Subject: [PATCH 031/133] Update proposals (#248) --- Documentation/Evolution/ProposalOverview.md | 55 +++++++++++++++++++ Documentation/Evolution/RegexSyntax.md | 57 ++++++++++++++++---- Documentation/Evolution/RegexTypeOverview.md | 2 +- 3 files changed, 102 insertions(+), 12 deletions(-) create mode 100644 Documentation/Evolution/ProposalOverview.md diff --git a/Documentation/Evolution/ProposalOverview.md b/Documentation/Evolution/ProposalOverview.md new file mode 100644 index 000000000..24ac0301c --- /dev/null +++ b/Documentation/Evolution/ProposalOverview.md @@ -0,0 +1,55 @@ + +# Regex Proposals + +## Regex Type and Overview + +- [Pitch](https://forums.swift.org/t/pitch-regex-type-and-overview/56029) +- Proposal: To-be-scheduled + +Presents basic Regex type and gives an overview of how everything fits into the overall story + + +## Regex Builder DSL + +- [Pitch thread](https://forums.swift.org/t/pitch-regex-builder-dsl/56007) + +Covers the result builder approach and basic API. + + +## Run-time Regex Construction + +- Pitch thread: [Regex Syntax](https://forums.swift.org/t/pitch-regex-syntax/55711) + + Brief: Syntactic superset of PCRE2, Oniguruma, ICU, UTS\#18, etc. + +Covers the "interior" syntax, extended syntaxes, run-time construction of a regex from a string, and details of `AnyRegexOutput`. + +Note: The above pitch drills into the syntax, the revised pitch including two initializers and existential details is still under development. + +## Regex Literals + +- [Draft](https://github.com/apple/swift-experimental-string-processing/pull/187) +- (Old) original pitch: + + [Thread](https://forums.swift.org/t/pitch-regular-expression-literals/52820) + + [Update](https://forums.swift.org/t/pitch-regular-expression-literals/52820/90) + + +## String processing algorithms + +- [Pitch thread](https://forums.swift.org/t/pitch-regex-powered-string-processing-algorithms/55969) + +Proposes a slew of Regex-powered algorithms. + +Introduces `CustomMatchingRegexComponent`, which is a monadic-parser style interface for external parsers to be used as components of a regex. + +## Unicode for String Processing + +- Draft: TBD +- (Old) [Character class definitions](https://forums.swift.org/t/pitch-character-classes-for-string-processing/52920) + +Covers three topics: + +- Proposes literal and DSL API for library-defined character classes, Unicode scripts and properties, and custom character classes. +- Proposes literal and DSL API for options that affect matching behavior. +- Defines how Unicode scalar-based classes are extended to grapheme clusters in the different semantic and other matching modes. + + diff --git a/Documentation/Evolution/RegexSyntax.md b/Documentation/Evolution/RegexSyntax.md index faa327176..9f4c6e8a0 100644 --- a/Documentation/Evolution/RegexSyntax.md +++ b/Documentation/Evolution/RegexSyntax.md @@ -10,27 +10,56 @@ Hello, we want to issue an update to [Regular Expression Literals](https://forum A regex declares a string processing algorithm using syntax familiar across a variety of languages and tools throughout programming history. We propose the ability to create a regex at run time from a string containing regex syntax (detailed here), API for accessing the match and captures, and a means to convert between an existential capture representation and concrete types. -The overall story is laid out in [Regex Type and Overview](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexTypeOverview.md) and each individual component is tracked in [Pitch and Proposal Status](https://github.com/apple/swift-experimental-string-processing/issues/107). +The overall story is laid out in [Regex Type and Overview][overview] and each individual component is tracked in [Pitch and Proposal Status](https://github.com/apple/swift-experimental-string-processing/issues/107). ## Motivation Swift aims to be a pragmatic programming language, striking a balance between familiarity, interoperability, and advancing the art. Swift's `String` presents a uniquely Unicode-forward model of string, but currently suffers from limited processing facilities. - +`NSRegularExpression` can construct a processing pipeline from a string containing [ICU regular expression syntax][icu-syntax]. However, it is inherently tied to ICU's engine and thus it operates over a fundamentally different model of string than Swift's `String`. It is also limited in features and carries a fair amount of Objective-C baggage. + +```swift +let pattern = #"(\w+)\s\s+(\S+)\s\s+((?:(?!\s\s).)*)\s\s+(.*)"# +let nsRegEx = try! NSRegularExpression(pattern: pattern) -The full string processing effort includes a regex type with strongly typed captures, the ability to create a regex from a string at runtime, a compile-time literal, a result builder DSL, protocols for intermixing 3rd party industrial-strength parsers with regex declarations, and a slew of regex-powered algorithms over strings. +func processEntry(_ line: String) -> Transaction? { + let range = NSRange(line.startIndex.. +We propose run-time construction of `Regex` from a best-in-class treatment of familiar regular expression syntax. A `Regex` is generic over its `Output`, which includes capture information. This may be an existential `AnyRegexOutput`, or a concrete type provided by the user. + +```swift +let pattern = #"(\w+)\s\s+(\S+)\s\s+((?:(?!\s\s).)*)\s\s+(.*)"# +let regex = try! Regex(compiling: pattern) +// regex: Regex + +let regex: Regex<(Substring, Substring, Substring, Substring, Substring)> = + try! Regex(compiling: pattern) +``` + ### Syntax @@ -866,3 +895,9 @@ This proposal regards _syntactic_ support, and does not necessarily mean that ev [unicode-scripts]: https://www.unicode.org/reports/tr24/#Script [unicode-script-extensions]: https://www.unicode.org/reports/tr24/#Script_Extensions [balancing-groups]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/grouping-constructs-in-regular-expressions#balancing-group-definitions +[overview]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexTypeOverview.md +[pitches]: https://github.com/apple/swift-experimental-string-processing/issues/107 + + + + diff --git a/Documentation/Evolution/RegexTypeOverview.md b/Documentation/Evolution/RegexTypeOverview.md index 504111181..55e9963cc 100644 --- a/Documentation/Evolution/RegexTypeOverview.md +++ b/Documentation/Evolution/RegexTypeOverview.md @@ -14,7 +14,7 @@ We propose addressing this basic shortcoming through an effort we are calling re 3. A literal for compile-time construction of a regex with statically-typed captures, enabling powerful source tools. 4. An expressive and composable result-builder DSL, with support for capturing strongly-typed values. 5. A modern treatment of Unicode semantics and string processing. -6. A treasure trove of string processing algorithms, along with library-extensible protocols enabling industrial-strength parsers to be used seamlessly as regex components. +6. A slew of regex-powered string processing algorithms, along with library-extensible protocols enabling industrial-strength parsers to be used seamlessly as regex components. This proposal provides details on \#1, the `Regex` type and captures, and gives an overview of how each of the other proposals fit into regex in Swift. From d56d7067972214062268142ebfe4e65a7f4597fc Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Mon, 4 Apr 2022 17:35:36 -0600 Subject: [PATCH 032/133] Update status link (#249) --- Documentation/Evolution/RegexTypeOverview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/Evolution/RegexTypeOverview.md b/Documentation/Evolution/RegexTypeOverview.md index 55e9963cc..819311cba 100644 --- a/Documentation/Evolution/RegexTypeOverview.md +++ b/Documentation/Evolution/RegexTypeOverview.md @@ -1,7 +1,7 @@ # Regex Type and Overview -- Authors: [Michael Ilseman](https://github.com/milseman) and the Standard Library Team +- Authors: [Michael Ilseman](https://github.com/milseman) ## Introduction @@ -545,4 +545,4 @@ Regexes are often used for tokenization and tokens can be represented with Swift --> -[pitches]: https://github.com/apple/swift-experimental-string-processing/issues/107 +[pitches]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/ProposalOverview.md From d57107b376e278913737a3a8be7b8411982af1b9 Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Mon, 4 Apr 2022 18:35:35 -0700 Subject: [PATCH 033/133] Update DSL proposal. - Removed `if` support. - Added `Local`. - Added alternatives. --- Documentation/Evolution/RegexBuilderDSL.md | 312 +++++++++------------ 1 file changed, 129 insertions(+), 183 deletions(-) diff --git a/Documentation/Evolution/RegexBuilderDSL.md b/Documentation/Evolution/RegexBuilderDSL.md index f0a477644..bd3bb08aa 100644 --- a/Documentation/Evolution/RegexBuilderDSL.md +++ b/Documentation/Evolution/RegexBuilderDSL.md @@ -17,6 +17,7 @@ - [Quantification](#quantification) - [Capture and reference](#capture-and-reference) - [Subpattern](#subpattern) + - [Scoping](#scoping) - [Source compatibility](#source-compatibility) - [Effect on ABI stability](#effect-on-abi-stability) - [Effect on API resilience](#effect-on-api-resilience) @@ -400,95 +401,7 @@ extension RegexComponentBuilder { } ``` -To support `if` statements, `buildEither(first:)`, `buildEither(second:)` and `buildOptional(_:)` are defined with overloads to support up to 10 captures because each capture type needs to be transformed to an optional. The overload for non-capturing regexes, due to the lack of generic constraints, must be annotated with `@_disfavoredOverload` in order not shadow other overloads. We expect that a variadic-generic version of this method will eventually superseded all of these overloads. - -```swift -extension RegexComponentBuilder { - // The following builder methods implement what would be possible with - // variadic generics (using imaginary syntax) as a single method: - // - // public static func buildEither< - // Component, WholeMatch, Capture... - // >( - // first component: Component - // ) -> Regex<(Substring, Capture...)> - // where Component.Output == (WholeMatch, Capture...) - - public static func buildEither( - first component: Component - ) -> Regex { - component - } - - public static func buildEither( - first component: Component - ) -> Regex<(Substring, C0)> where R.Output == (W, C0) { - component - } - - public static func buildEither( - first component: Component - ) -> Regex<(Substring, C0, C1)> where R.Output == (W, C0, C1) { - component - } - - // The following builder methods implement what would be possible with - // variadic generics (using imaginary syntax) as a single method: - // - // public static func buildEither< - // Component, WholeMatch, Capture... - // >( - // second component: Component - // ) -> Regex<(Substring, Capture...)> - // where Component.Output == (WholeMatch, Capture...) - - public static func buildEither( - second component: Component - ) -> Regex { - component - } - - public static func buildEither( - second component: Component - ) -> Regex<(Substring, C0)> where R.Output == (W, C0) { - component - } - - public static func buildEither( - second component: Component - ) -> Regex<(Substring, C0, C1)> where R.Output == (W, C0, C1) { - component - } - - // ... `O(arity)` overloads of `buildEither(_:)` - - // The following builder methods implement what would be possible with - // variadic generics (using imaginary syntax) as a single method: - // - // public static func buildOptional< - // Component, WholeMatch, Capture... - // >( - // _ component: Component? - // ) where Component.Output == (WholeMatch, Capture...) - - @_disfavoredOverload - public static func buildOptional( - _ component: Component? - ) -> Regex - - public static func buildOptional( - _ component: Component? - ) -> Regex<(Substring, C0?)> - - public static func buildOptional( - _ component: Component? - ) -> Regex<(Substring, C0?, C1?)> - - // ... `O(arity)` overloads of `buildOptional(_:)` -} -``` - -To support `if #available(...)` statements, `buildLimitedAvailability(_:)` is defined with overloads to support up to 10 captures. Similar to `buildOptional`, the overload for non-capturing regexes must be annotated with `@_disfavoredOverload`. +To support `if #available(...)` statements, `buildLimitedAvailability(_:)` is defined with overloads to support up to 10 captures. The overload for non-capturing regexes, due to the lack of generic constraints, must be annotated with `@_disfavoredOverload` in order not shadow other overloads. We expect that a variadic-generic version of this method will eventually superseded all of these overloads. ```swift extension RegexComponentBuilder { @@ -518,6 +431,8 @@ extension RegexComponentBuilder { } ``` +`buildOptional` and `buildEither` are intentionally not supported due to ergonomic issues and fundamental semantic differences between regex conditionals and result builder conditionals. Please refer to the [alternatives considered](#support-buildoptional-and-buildeither) section for detailed rationale. + ### Alternation Alternations are used to match one of multiple patterns. An alternation wraps its underlying patterns' capture types in an `Optional` and concatenates them together, first to last. @@ -620,99 +535,6 @@ public enum AlternationBuilder { // ... `O(arity^2)` overloads of `buildPartialBlock(accumulated:next:)` } -extension AlternationBuilder { - // The following builder methods implement what would be possible with - // variadic generics (using imaginary syntax) as a single method: - // - // public static func buildEither< - // R, WholeMatch, Capture... - // >( - // first component: Component - // ) -> Regex<(Substring, Component?...)> - // where R.Output == (WholeMatch, Capture...) - - @_disfavoredOverload - public static func buildEither( - first component: Component - ) -> Regex - - public static func buildEither( - first component: Component - ) -> Regex<(Substring, C0?)> - - public static func buildEither( - first component: Component - ) -> Regex<(Substring, C0?, C1?)> - - // ... `O(arity)` overloads of `buildEither(_:)` - - public static func buildEither( - first component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8, C9?)> where R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) -} - -extension AlternationBuilder { - // The following builder methods implement what would be possible with - // variadic generics (using imaginary syntax) as a single method: - // - // public static func buildEither< - // R, WholeMatch, Capture... - // >( - // second component: Component - // ) -> Regex<(Substring, Capture?...)> - // where R.Output == (WholeMatch, Capture...) - - @_disfavoredOverload - public static func buildEither( - second component: Component - ) -> Regex - - public static func buildEither( - second component: Component - ) -> Regex<(Substring, C0?)> - - public static func buildEither( - second component: Component - ) -> Regex<(Substring, C0?, C1?)> - - // ... `O(arity)` overloads of `buildEither(_:)` - - public static func buildEither( - second component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8, C9?)> where R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) -} - -extension AlternationBuilder { - // The following builder methods implement what would be possible with - // variadic generics (using imaginary syntax) as a single method: - // - // public static func buildOptional< - // Component, WholeMatch, Capture... - // >( - // _ component: Component? - // ) -> Regex<(Substring, Capture?...)> - // where Component.Output == (WholeMatch, Capture...) - - @_disfavoredOverload - public static func buildOptional( - _ component: Component? - ) -> Regex - - public static func buildOptional( - _ component: Component? - ) -> Regex<(Substring, C0?)> - - public static func buildOptional( - _ component: Component? - ) -> Regex<(Substring, C0?, C1?)> - - // ... `O(arity)` overloads of `buildOptional(_:)` - - public static func buildOptional( - _ component: Component? - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8, C9?)> where R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) -} - extension AlternationBuilder { // The following builder methods implement what would be possible with // variadic generics (using imaginary syntax) as a single method: @@ -1290,6 +1112,53 @@ Regex { wholeSentence in } ``` +### Scoping + +In textual regexes, atomic groups (`(?>...)`) can be used to define a backtracking scope. That is, when the regex engine exits from the scope successfully, it throws away all backtracking positions from the scope. In regex builder, the `Local` type serves this purpose. + +```swift +public struct Local: RegexComponent { + public var regex: Regex + + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single set of methods: + // + // public init( + // @RegexComponentBuilder _ component: () -> Component + // ) where Output == (Substring, Capture...), Component.Output == (WholeMatch, Capture...) + + @_disfavoredOverload + public init( + @RegexComponentBuilder _ component: () -> Component + ) where Output == Substring + + public init( + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0), Component.Output == (W, C0) + + public init( + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0, C1), Component.Output == (W, C0, C1) + + // ... `O(arity)` overloads +} +``` + +For example, the following regex matches string `abcc` but not `abc`. + +```swift +Regex { + "a" + Local { + ChoiceOf { + "bc" + "b" + } + } + "c" +} +``` + ## Source compatibility Regex builder will be shipped in a new module named `RegexBuilder`, and thus will not affect the source compatibility of the existing code. @@ -1306,7 +1175,7 @@ The proposed feature relies heavily upon overloads of `buildBlock` and `buildPar ### Operators for quantification and alternation -While `ChoiceOf` and quantifier functions provide a general way of creating alternations and quantifications, we recognize that some synctactic sugar can be useful for creating one-liners like in textual regexes, e.g. infix operator `|`, postfix operator `*`, etc. +While `ChoiceOf` and quantifier types provide a general way of creating alternations and quantifications, we recognize that some synctactic sugar can be useful for creating one-liners like in textual regexes, e.g. infix operator `|`, postfix operator `*`, etc. ```swift // The following functions implement what would be possible with variadic @@ -1441,6 +1310,83 @@ One could argue that type such as `OneOrMore` could be defined as a top- Another reason to use types instead of free functions is consistency with existing result-builder-based DSLs such as SwiftUI. +### Support `buildOptional` and `buildEither` + +To support `if` statements, an earlier iteration of this proposal defined `buildEither(first:)`, `buildEither(second:)` and `buildOptional(_:)` as the following: + +```swift +extension RegexComponentBuilder { + public static func buildEither< + Component, WholeMatch, Capture... + >( + first component: Component + ) -> Regex<(Substring, Capture...)> + where Component.Output == (WholeMatch, Capture...) + + public static func buildEither< + Component, WholeMatch, Capture... + >( + second component: Component + ) -> Regex<(Substring, Capture...)> + where Component.Output == (WholeMatch, Capture...) + + public static func buildOptional< + Component, WholeMatch, Capture... + >( + _ component: Component? + ) where Component.Output == (WholeMatch, Capture...) +} +``` + +However, multiple-branch control flow statements (e.g. `if`-`else` and `switch`) would need to be required to produce either the same regex type, which is limiting, or an "either-like" type, which can be difficult to work with when nested. Unlike `ChoiceOf`, producing a tuple of optionals is not an option, because the branch taken would be decided when the builder closure is executed, and it would cause capture numbering to be inconsistent with conventional regex. + +Moreover, result builder conditionals does not work the same way as regex conditionals. In regex conditionals, the conditions are themselves regexes and are evaluated by the regex engine during matching, whereas result builder conditionals are evaluated as part of the builder closure. We hope that a future result builder feature will support "lifting" control flow conditions into the DSL domain, e.g. supporting `Regex` as a condition. + +### Flatten optionals + +With the proposed design, `ChoiceOf` with `AlternationBuilder` wraps every component's capture type with an `Optional`. This means that any `ChoiceOf` with optional-capturing components would lead to a doubly-nested optional captures. This could make the result of matching harder to use. + +```swift +ChoiceOf { + OneOrMore(Capture(.digit)) // Output == (Substring, Substring) + Optionally { + ZeroOrMore(Capture(.word)) // Output == (Substring, Substring?) + "a" + } // Output == (Substring, Substring??) +} // Output == (Substring, Substring?, Substring???) +``` + +One way to improve this could be overloading quantifier initializers (e.g. `ZeroOrMore.init(_:)`) and `AlternationBuilder.buildPartialBlock` to flatten any optionals upon composition. However, this would be non-trivial. Quantifier initializers would need to be overloaded `O(2^arity)` times to account for all possible positions of `Optional` that may appear in the `Output` tuple. Even worse, `AlternationBuilder.buildPartialBlock` would need to be overloaded `O(arity!)` times to account for all possible combinations of two `Output` tuples with all possible positions of `Optional` that may appear in one of the `Output` tuples. + +### Structured rather than flat captures + +We propose inferring capture types in such a way as to align with the traditional numbering of backreferences. This is because much of the motivation behind providing regex in Swift is their familiarity. + +If we decided to deprioritize this motivation, there are opportunities to infer safer, more ergonomic, and arguably more intuitive types for captures. For example, to be consistent with traditional regex backreferences quantifications of multiple or nested captures had to produce parallel arrays rather than an array of tuples. + +```swift +OneOrMore { + Capture { + OneOrMore(.hexDigit) + } + ".." + Capture { + OneOrMore(.hexDigit) + } +} + +// Flat capture types: +// => `Output == (Substring, Substring, Substring)>` + +// Structured capture types: +// => `Output == (Substring, (Substring, Substring))` +``` + +Similarly, an alternation of multiple or nested captures could produce a structured alternation type (or an anonymous sum type) rather than flat optionals. + +This is cool, but it adds extra complexity to regex builder and it isn't as clear because the generic type no longer aligns with the traditional regex backreference numbering. We think the consistency of the flat capture types trumps the added safety and ergonomics of the structured capture types. + + [Declarative String Processing]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/DeclarativeStringProcessing.md [Strongly Typed Regex Captures]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/StronglyTypedCaptures.md [Regex Syntax]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntax.md From 5ec50014fd628a91ee064ee40b47c576a369fb95 Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Mon, 4 Apr 2022 18:45:38 -0700 Subject: [PATCH 034/133] Complete list of authors --- Documentation/Evolution/RegexBuilderDSL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Evolution/RegexBuilderDSL.md b/Documentation/Evolution/RegexBuilderDSL.md index bd3bb08aa..635112e93 100644 --- a/Documentation/Evolution/RegexBuilderDSL.md +++ b/Documentation/Evolution/RegexBuilderDSL.md @@ -1,7 +1,7 @@ # Regex builder DSL * Proposal: [SE-NNNN](NNNN-filename.md) -* Authors: [Richard Wei](https://github.com/rxwei) +* Authors: [Richard Wei](https://github.com/rxwei), [Michael Ilseman](https://github.com/milseman), [Nate Cook](https://github.com/natecook1000) * Review Manager: TBD * Implementation: [apple/swift-experimental-string-processing](https://github.com/apple/swift-experimental-string-processing/tree/main/Sources/_StringProcessing/RegexDSL) * Status: **Pitch** From b78d7d02a85fac148c7bd6dfb3c5a287bcaaab97 Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Mon, 4 Apr 2022 19:35:45 -0700 Subject: [PATCH 035/133] Add `Regex` alternative to regex proposal --- Documentation/Evolution/RegexTypeOverview.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/Evolution/RegexTypeOverview.md b/Documentation/Evolution/RegexTypeOverview.md index 504111181..5bc727db1 100644 --- a/Documentation/Evolution/RegexTypeOverview.md +++ b/Documentation/Evolution/RegexTypeOverview.md @@ -482,6 +482,12 @@ We're also looking for more community discussion on what the default type system The actual `Match` struct just stores ranges: the `Substrings` are lazily created on demand. This avoids unnecessary ARC traffic and memory usage. +### `Regex` instead of `Regex` + +The generic parameter `Output` is proposed to contain both the whole match (the `.0` element if `Output` is a tuple) and captures. One alternative we have considered is separating `Output` into the entire match and the captures, i.e. `Regex`, and using `Void` for for `Captures` when there are no captures. + +The biggest issue with this alternative design is that the numbering of `Captures` elements misaligns with the numbering of captures in textual regexes, where backreference `\0` refers to the entire match and captures start at `\1`. This design would sacrifice familarity and have the pitfall of introducing off-by-one errors. + ### Future work: static optimization and compilation Swift's support for static compilation is still developing, and future work here is leveraging that to compile regex when profitable. Many regex describe simple [DFAs](https://en.wikipedia.org/wiki/Deterministic_finite_automaton) and can be statically compiled into very efficient programs. Full static compilation needs to be balanced with code size concerns, as a matching-specific bytecode is typically far smaller than a corresponding program (especially since the bytecode interpreter is shared). From 45e8a1f778a6687a3fcb9233a42124fb1bd8d42a Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 5 Apr 2022 10:50:24 +0100 Subject: [PATCH 036/133] Fix HexDigit definition in RegexSyntax.md --- Documentation/Evolution/RegexSyntax.md | 2 +- Tests/RegexTests/ParseTests.swift | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/Evolution/RegexSyntax.md b/Documentation/Evolution/RegexSyntax.md index 9f4c6e8a0..97e3b45da 100644 --- a/Documentation/Evolution/RegexSyntax.md +++ b/Documentation/Evolution/RegexSyntax.md @@ -263,7 +263,7 @@ UnicodeScalar -> '\u{' HexDigit{1...} '}' | '\o{' OctalDigit{1...} '}' | '\0' OctalDigit{0...3} -HexDigit -> [0-9a-zA-Z] +HexDigit -> [0-9a-fA-F] OctalDigit -> [0-7] NamedScalar -> '\N{' ScalarName '}' diff --git a/Tests/RegexTests/ParseTests.swift b/Tests/RegexTests/ParseTests.swift index c6ff3e46d..5e3defb11 100644 --- a/Tests/RegexTests/ParseTests.swift +++ b/Tests/RegexTests/ParseTests.swift @@ -2313,6 +2313,10 @@ extension RegexTests { diagnosticTest("{5}", .quantifierRequiresOperand("{5}")) diagnosticTest("{1,3}", .quantifierRequiresOperand("{1,3}")) + // MARK: Unicode scalars + + diagnosticTest(#"\u{G}"#, .expectedNumber("G", kind: .hex)) + // MARK: Matching options diagnosticTest(#"(?^-"#, .cannotRemoveMatchingOptionsAfterCaret) From 0a9447a00f24e44daa0fd6f5e8c537e066cd462f Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 6 Apr 2022 11:41:26 +0100 Subject: [PATCH 037/133] Update typed captures section + other tweaks --- Documentation/Evolution/DelimiterSyntax.md | 32 +++++++++++++--------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 0a86e170e..39cf87551 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -4,7 +4,7 @@ ## Introduction -This proposal helps complete the story told in [Regex Type and Overview][regex-type] and [elsewhere][pitch-status]. We propose the introduction of regex literals to Swift source code. The proposed syntax mirrors literals in other programing languages such as Perl, JavaScript and Ruby. As in those languages, literals are delimited with the `/` character: +This proposal helps complete the story told in *[Regex Type and Overview][regex-type]* and [elsewhere][pitch-status]. We propose the introduction of regex literals to Swift source code. The proposed syntax mirrors literals in other programing languages such as Perl, JavaScript and Ruby. As in those languages, literals are delimited with the `/` character: ```swift let re = /[0-9]+/ @@ -12,7 +12,7 @@ let re = /[0-9]+/ ## Motivation -In [Regex Type and Overview][regex-type] we introduced the `Regex` type, which is able to dynamically compile a regex pattern: +In *[Regex Type and Overview][regex-type]* we introduced the `Regex` type, which is able to dynamically compile a regex pattern: ```swift let pattern = #"(\w+)\s\s+(\S+)\s\s+((?:(?!\s\s).)*)\s\s+(.*)"# @@ -41,7 +41,7 @@ Forward slashes are a regex term of art, and are used as the delimiters for rege A regex literal may also be spelled using an extended syntax `#/.../#`, which allows the placement of an arbitrary number of balanced `#` characters around the literal. This syntax may be used to avoid needing to escape forward slashes within the regex. Additionally, it allows for a multi-line mode when the opening delimiter is followed by a new line. -Within a regex literal, the compiler will parse the regex syntax outlined in in [the Regex Syntax pitch][internal-syntax], and diagnose any errors at compile time. The capture types and labels are automatically inferred based on the capture groups present in the regex. Using a literal allows editors to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see [Regex builder DSL][regex-dsl]). +Within a regex literal, the compiler will parse the regex syntax outlined in *[Regex Construction][internal-syntax]*, and diagnose any errors at compile time. The capture types and labels are automatically inferred based on the capture groups present in the regex. Using a literal allows editors to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see *[Regex builder DSL][regex-dsl]*). A regex literal also allows for seamless composition with the Regex DSL, enabling lightweight intermixing of a regex syntax with other elements of the builder: @@ -67,9 +67,9 @@ Due to the existing use of `/` in comment syntax and operators, there are some s Due to the source breaking changes needed for the `/.../` syntax, it will be introduced in Swift 6 mode. However, projects will be able to adopt it earlier by using the compiler flag `-enable-regex-literals`. Note this does not affect the extended syntax `#/.../#`, which will be usable immediately. -### Typed captures +### Named typed captures -Regex literals have their capture types statically determined by the capture groups present. A initial `Substring` is always present for the entire match, and each capture group adds an additional capture to the match tuple, with named capture groups receiving a corresponding tuple label. Once matched, such captures may later be referenced: +Regex literals have their capture types statically determined by the capture groups present. This follows the same inference behavior as [the DSL][regex-dsl], and is explored in more detail in *[Strongly Typed Captures][strongly-typed-captures]*. One aspect of this that is currently unique to the literal is the ability to infer labeled tuple elements for named capture groups. For example: ```swift func matchHexAssignment(_ input: String) -> (String, Int)? { @@ -84,9 +84,7 @@ func matchHexAssignment(_ input: String) -> (String, Int)? { } ``` -Unnamed capture groups produce unlabeled tuple elements and must be referenced by their position, e.g `match.1`, `match.2`. See [StronglyTypedCaptures.md](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/StronglyTypedCaptures.md) for more info. - -**TODO: Should we cover more general typed capture behavior from [StronglyTypedCaptures.md](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/StronglyTypedCaptures.md) here? There is some overlap with the typed capture behavior of the DSL tho, labels are the main thing that are literal specific** +This allows the captures to be referenced as `match.identifier` and `match.hex` instead of `match.1` and `match.2`, which would be the behavior for unnamed capture groups. This label inference behavior is not available in the DSL, however users are able to [bind captures to named variables instead][dsl-captures]. ### Extended delimiters `#/.../#`, `##/.../##` @@ -288,7 +286,9 @@ This takes advantage of the fact that a regex literal will not be parsed if the ### Modern literal syntax -We could support a more modern Swift-like syntax in regex literals. For example, comments could be done with `//` and `/* ... */`, and quoted sequences could be done with `"..."`. This would however be incompatible with the syntactic superset of regex syntax we intend to parse, and as such may need to be introduced using a new literal kind, with no obvious choice of delimiter. However, it's possible that the ability to use regex literals in the DSL lessens the benefit that this syntax would bring. +We could support a more modern Swift-like syntax in regex literals. For example, comments could be done with `//` and `/* ... */`, and quoted sequences could be done with `"..."`. This would however be incompatible with the syntactic superset of regex syntax we intend to parse, and as such may need to be introduced using a new literal kind, with no obvious choice of delimiter. + +However, such a syntax would lose out on the familiarity benefits of standard regex, and as such may lead to an "uncanny valley" effect. It's also possible that the ability to use regex literals in the DSL lessens the benefit that this syntax would bring. ## Alternatives Considered @@ -368,8 +368,14 @@ We therefore feel this would be a much less compelling feature without first cla [SE-0168]: https://github.com/apple/swift-evolution/blob/main/proposals/0168-multi-line-string-literals.md [SE-0200]: https://github.com/apple/swift-evolution/blob/main/proposals/0200-raw-string-escaping.md -[internal-syntax]: https://forums.swift.org/t/pitch-regex-syntax/55711 -[regex-type]: https://forums.swift.org/t/pitch-regex-type-and-overview/56029 -[pitch-status]: https://github.com/apple/swift-experimental-string-processing/issues/107 -[regex-dsl]: https://forums.swift.org/t/pitch-regex-builder-dsl/56007 + +[pitch-status]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/ProposalOverview.md +[regex-type]: https://github.com/apple/swift-evolution/blob/main/proposals/0350-regex-type-overview.md +[strongly-typed-captures]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/StronglyTypedCaptures.md + +[internal-syntax]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntax.md [extended-regex-syntax]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntax.md#extended-syntax-modes + +[regex-dsl]: https://github.com/apple/swift-evolution/blob/main/proposals/0351-regex-builder.md +[dsl-captures]: https://github.com/apple/swift-evolution/blob/main/proposals/0351-regex-builder.md#capture-and-reference + From 52bc9322e27566d1dcd4dbd118f27f07ccb43af7 Mon Sep 17 00:00:00 2001 From: Tina Liu <49205802+itingliu@users.noreply.github.com> Date: Thu, 7 Apr 2022 12:47:23 -0700 Subject: [PATCH 038/133] Clean up based on the String Processing Algorithms proposal (#247) * Clean up based on the String Processing Algorithms proposal - Move functions and types that have not been proposed from public to internal - Add doc comments for public API - Add FIXME for API awaiting SE-0346 - Replace `_MatchResult` with `Regex.Match` and update tests Co-authored-by: Richard Wei --- .../Algorithms/Algorithms/Contains.swift | 14 ++- .../Algorithms/Algorithms/FirstRange.swift | 21 ++++- .../Algorithms/Algorithms/Ranges.swift | 26 +++--- .../Algorithms/Algorithms/Replace.swift | 71 ++++++++++++--- .../Algorithms/Algorithms/Split.swift | 40 ++++++--- .../Algorithms/Algorithms/StartsWith.swift | 15 ++-- .../Algorithms/Algorithms/Trim.swift | 78 ++++++++++------ .../Consumers/CollectionConsumer.swift | 12 +-- .../Algorithms/Matching/FirstMatch.swift | 19 +++- .../Algorithms/Matching/MatchReplace.swift | 90 +++++++++++++++++-- .../Algorithms/Matching/MatchResult.swift | 16 ++-- .../Algorithms/Matching/Matches.swift | 43 ++++++--- .../Matching/MatchingCollectionConsumer.swift | 8 +- .../Matching/MatchingCollectionSearcher.swift | 20 ++--- .../Searchers/CollectionSearcher.swift | 18 ++-- .../Algorithms/Searchers/PatternOrEmpty.swift | 10 +-- Tests/RegexBuilderTests/AlgorithmsTests.swift | 20 +++-- Tests/RegexBuilderTests/CustomTests.swift | 12 +-- Tests/RegexBuilderTests/RegexDSLTests.swift | 8 +- 19 files changed, 387 insertions(+), 154 deletions(-) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift index dbe7923ec..46568192f 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift @@ -12,7 +12,7 @@ // MARK: `CollectionSearcher` algorithms extension Collection { - public func contains( + func contains( _ searcher: Searcher ) -> Bool where Searcher.Searched == Self { firstRange(of: searcher) != nil @@ -22,6 +22,11 @@ extension Collection { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { + /// Returns a Boolean value indicating whether the collection contains the + /// given sequence. + /// - Parameter other: A sequence to search for within this collection. + /// - Returns: `true` if the collection contains the specified sequence, + /// otherwise `false`. public func contains(_ other: S) -> Bool where S.Element == Element { @@ -30,7 +35,7 @@ extension Collection where Element: Equatable { } extension BidirectionalCollection where Element: Comparable { - public func contains(_ other: S) -> Bool + func contains(_ other: S) -> Bool where S.Element == Element { firstRange(of: other) != nil @@ -40,6 +45,11 @@ extension BidirectionalCollection where Element: Comparable { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { + /// Returns a Boolean value indicating whether the collection contains the + /// given regex. + /// - Parameter regex: A regex to search for within this collection. + /// - Returns: `true` if the regex was found in the collection, otherwise + /// `false`. public func contains(_ regex: R) -> Bool { contains(RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift index 40d5b9950..405fe47ef 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift @@ -12,7 +12,7 @@ // MARK: `CollectionSearcher` algorithms extension Collection { - public func firstRange( + func firstRange( of searcher: S ) -> Range? where S.Searched == Self { var state = searcher.state(for: self, in: startIndex..( + func lastRange( of searcher: S ) -> Range? where S.BackwardSearched == Self { var state = searcher.backwardState(for: self, in: startIndex..( of sequence: S ) -> Range? where S.Element == Element { @@ -42,6 +47,11 @@ extension Collection where Element: Equatable { } extension BidirectionalCollection where Element: Comparable { + /// Finds and returns the range of the first occurrence of a given sequence + /// within the collection. + /// - Parameter other: The sequence to search for. + /// - Returns: A range in the collection of the first occurrence of `sequence`. + /// Returns `nil` if `sequence` is not found. public func firstRange( of other: S ) -> Range? where S.Element == Element { @@ -56,11 +66,16 @@ extension BidirectionalCollection where Element: Comparable { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { + /// Finds and returns the range of the first occurrence of a given regex + /// within the collection. + /// - Parameter regex: The regex to search for. + /// - Returns: A range in the collection of the first occurrence of `regex`. + /// Returns `nil` if `regex` is not found. public func firstRange(of regex: R) -> Range? { firstRange(of: RegexConsumer(regex)) } - public func lastRange(of regex: R) -> Range? { + func lastRange(of regex: R) -> Range? { lastRange(of: RegexConsumer(regex)) } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift index e56e35e72..3a45b86a2 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift @@ -11,7 +11,7 @@ // MARK: `RangesCollection` -public struct RangesCollection { +struct RangesCollection { public typealias Base = Searcher.Searched let base: Base @@ -33,7 +33,7 @@ public struct RangesCollection { } } -public struct RangesIterator: IteratorProtocol { +struct RangesIterator: IteratorProtocol { public typealias Base = Searcher.Searched let base: Base @@ -92,7 +92,7 @@ extension RangesCollection: Collection { } extension RangesCollection.Index: Comparable { - public static func == (lhs: Self, rhs: Self) -> Bool { + static func == (lhs: Self, rhs: Self) -> Bool { switch (lhs.range, rhs.range) { case (nil, nil): return true @@ -103,7 +103,7 @@ extension RangesCollection.Index: Comparable { } } - public static func < (lhs: Self, rhs: Self) -> Bool { + static func < (lhs: Self, rhs: Self) -> Bool { switch (lhs.range, rhs.range) { case (nil, _): return false @@ -117,8 +117,8 @@ extension RangesCollection.Index: Comparable { // MARK: `ReversedRangesCollection` -public struct ReversedRangesCollection { - public typealias Base = Searcher.BackwardSearched +struct ReversedRangesCollection { + typealias Base = Searcher.BackwardSearched let base: Base let searcher: Searcher @@ -157,7 +157,7 @@ extension ReversedRangesCollection: Sequence { // MARK: `CollectionSearcher` algorithms extension Collection { - public func ranges( + func ranges( of searcher: S ) -> RangesCollection where S.Searched == Self { RangesCollection(base: self, searcher: searcher) @@ -165,7 +165,7 @@ extension Collection { } extension BidirectionalCollection { - public func rangesFromBack( + func rangesFromBack( of searcher: S ) -> ReversedRangesCollection where S.BackwardSearched == Self { ReversedRangesCollection(base: self, searcher: searcher) @@ -175,7 +175,8 @@ extension BidirectionalCollection { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { - public func ranges( + // FIXME: Replace `RangesCollection` when SE-0346 is enabled + func ranges( of other: S ) -> RangesCollection> where S.Element == Element { ranges(of: ZSearcher(pattern: Array(other), by: ==)) @@ -194,7 +195,7 @@ extension BidirectionalCollection where Element: Equatable { } extension BidirectionalCollection where Element: Comparable { - public func ranges( + func ranges( of other: S ) -> RangesCollection>> where S.Element == Element @@ -216,13 +217,14 @@ extension BidirectionalCollection where Element: Comparable { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func ranges( + // FIXME: Replace `RangesCollection` when SE-0346 is enabled + func ranges( of regex: R ) -> RangesCollection> { ranges(of: RegexConsumer(regex)) } - public func rangesFromBack( + func rangesFromBack( of regex: R ) -> ReversedRangesCollection> { rangesFromBack(of: RegexConsumer(regex)) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift index e2c9d78a4..bc23a284c 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift @@ -12,7 +12,7 @@ // MARK: `CollectionSearcher` algorithms extension RangeReplaceableCollection { - public func replacing( + func replacing( _ searcher: Searcher, with replacement: Replacement, subrange: Range, @@ -36,7 +36,7 @@ extension RangeReplaceableCollection { return result } - public func replacing( + func replacing( _ searcher: Searcher, with replacement: Replacement, maxReplacements: Int = .max @@ -50,7 +50,7 @@ extension RangeReplaceableCollection { maxReplacements: maxReplacements) } - public mutating func replace< + mutating func replace< Searcher: CollectionSearcher, Replacement: Collection >( _ searcher: Searcher, @@ -67,6 +67,16 @@ extension RangeReplaceableCollection { // MARK: Fixed pattern algorithms extension RangeReplaceableCollection where Element: Equatable { + /// Returns a new collection in which all occurrences of a target sequence + /// are replaced by another collection. + /// - Parameters: + /// - other: The sequence to replace. + /// - replacement: The new elements to add to the collection. + /// - subrange: The range in the collection in which to search for `other`. + /// - maxReplacements: A number specifying how many occurrences of `other` + /// to replace. Default is `Int.max`. + /// - Returns: A new collection in which all occurrences of `other` in + /// `subrange` of the collection are replaced by `replacement`. public func replacing( _ other: S, with replacement: Replacement, @@ -79,7 +89,16 @@ extension RangeReplaceableCollection where Element: Equatable { subrange: subrange, maxReplacements: maxReplacements) } - + + /// Returns a new collection in which all occurrences of a target sequence + /// are replaced by another collection. + /// - Parameters: + /// - other: The sequence to replace. + /// - replacement: The new elements to add to the collection. + /// - maxReplacements: A number specifying how many occurrences of `other` + /// to replace. Default is `Int.max`. + /// - Returns: A new collection in which all occurrences of `other` in + /// `subrange` of the collection are replaced by `replacement`. public func replacing( _ other: S, with replacement: Replacement, @@ -91,7 +110,13 @@ extension RangeReplaceableCollection where Element: Equatable { subrange: startIndex..( _ other: S, with replacement: Replacement, @@ -108,7 +133,7 @@ extension RangeReplaceableCollection where Element: Equatable { extension RangeReplaceableCollection where Self: BidirectionalCollection, Element: Comparable { - public func replacing( + func replacing( _ other: S, with replacement: Replacement, subrange: Range, @@ -121,7 +146,7 @@ extension RangeReplaceableCollection maxReplacements: maxReplacements) } - public func replacing( + func replacing( _ other: S, with replacement: Replacement, maxReplacements: Int = .max @@ -133,7 +158,7 @@ extension RangeReplaceableCollection maxReplacements: maxReplacements) } - public mutating func replace( + mutating func replace( _ other: S, with replacement: Replacement, maxReplacements: Int = .max @@ -149,6 +174,16 @@ extension RangeReplaceableCollection // MARK: Regex algorithms extension RangeReplaceableCollection where SubSequence == Substring { + /// Returns a new collection in which all occurrences of a sequence matching + /// the given regex are replaced by another collection. + /// - Parameters: + /// - regex: A regex describing the sequence to replace. + /// - replacement: The new elements to add to the collection. + /// - subrange: The range in the collection in which to search for `regex`. + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - Returns: A new collection in which all occurrences of subsequence + /// matching `regex` in `subrange` are replaced by `replacement`. public func replacing( _ regex: R, with replacement: Replacement, @@ -161,7 +196,16 @@ extension RangeReplaceableCollection where SubSequence == Substring { subrange: subrange, maxReplacements: maxReplacements) } - + + /// Returns a new collection in which all occurrences of a sequence matching + /// the given regex are replaced by another collection. + /// - Parameters: + /// - regex: A regex describing the sequence to replace. + /// - replacement: The new elements to add to the collection. + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - Returns: A new collection in which all occurrences of subsequence + /// matching `regex` are replaced by `replacement`. public func replacing( _ regex: R, with replacement: Replacement, @@ -173,7 +217,14 @@ extension RangeReplaceableCollection where SubSequence == Substring { subrange: startIndex..( _ regex: R, with replacement: Replacement, diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift index 15c946ca2..898f93048 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -11,7 +11,7 @@ // MARK: `SplitCollection` -public struct SplitCollection { +struct SplitCollection { public typealias Base = Searcher.Searched let ranges: RangesCollection @@ -101,7 +101,7 @@ extension SplitCollection: Collection { } extension SplitCollection.Index: Comparable { - public static func == (lhs: Self, rhs: Self) -> Bool { + static func == (lhs: Self, rhs: Self) -> Bool { switch (lhs.isEndIndex, rhs.isEndIndex) { case (false, false): return lhs.start == rhs.start @@ -110,7 +110,7 @@ extension SplitCollection.Index: Comparable { } } - public static func < (lhs: Self, rhs: Self) -> Bool { + static func < (lhs: Self, rhs: Self) -> Bool { switch (lhs.isEndIndex, rhs.isEndIndex) { case (true, _): return false @@ -124,7 +124,7 @@ extension SplitCollection.Index: Comparable { // MARK: `ReversedSplitCollection` -public struct ReversedSplitCollection { +struct ReversedSplitCollection { public typealias Base = Searcher.BackwardSearched let ranges: ReversedRangesCollection @@ -175,7 +175,7 @@ extension ReversedSplitCollection: Sequence { // MARK: `CollectionSearcher` algorithms extension Collection { - public func split( + func split( by separator: Searcher ) -> SplitCollection where Searcher.Searched == Self { // TODO: `maxSplits`, `omittingEmptySubsequences`? @@ -184,7 +184,7 @@ extension Collection { } extension BidirectionalCollection { - public func splitFromBack( + func splitFromBack( by separator: Searcher ) -> ReversedSplitCollection where Searcher.BackwardSearched == Self @@ -197,7 +197,7 @@ extension BidirectionalCollection { extension Collection { // TODO: Non-escaping and throwing - public func split( + func split( whereSeparator predicate: @escaping (Element) -> Bool ) -> SplitCollection> { split(by: PredicateConsumer(predicate: predicate)) @@ -205,7 +205,7 @@ extension Collection { } extension BidirectionalCollection where Element: Equatable { - public func splitFromBack( + func splitFromBack( whereSeparator predicate: @escaping (Element) -> Bool ) -> ReversedSplitCollection> { splitFromBack(by: PredicateConsumer(predicate: predicate)) @@ -215,7 +215,7 @@ extension BidirectionalCollection where Element: Equatable { // MARK: Single element algorithms extension Collection where Element: Equatable { - public func split( + func split( by separator: Element ) -> SplitCollection> { split(whereSeparator: { $0 == separator }) @@ -223,7 +223,7 @@ extension Collection where Element: Equatable { } extension BidirectionalCollection where Element: Equatable { - public func splitFromBack( + func splitFromBack( by separator: Element ) -> ReversedSplitCollection> { splitFromBack(whereSeparator: { $0 == separator }) @@ -233,7 +233,13 @@ extension BidirectionalCollection where Element: Equatable { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { - public func split( + // FIXME: Replace `SplitCollection` when SE-0346 is enabled + /// Returns the longest possible subsequences of the collection, in order, + /// around elements equal to the given separator. + /// - Parameter separator: The element to be split upon. + /// - Returns: A collection of subsequences, split from this collection's + /// elements. + func split( by separator: S ) -> SplitCollection> where S.Element == Element { split(by: ZSearcher(pattern: Array(separator), by: ==)) @@ -252,7 +258,7 @@ extension BidirectionalCollection where Element: Equatable { } extension BidirectionalCollection where Element: Comparable { - public func split( + func split( by separator: S ) -> SplitCollection>> where S.Element == Element @@ -275,13 +281,19 @@ extension BidirectionalCollection where Element: Comparable { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func split( + // FIXME: Replace `SplitCollection` when SE-0346 is enabled + /// Returns the longest possible subsequences of the collection, in order, + /// around elements equal to the given separator. + /// - Parameter separator: A regex describing elements to be split upon. + /// - Returns: A collection of substrings, split from this collection's + /// elements. + func split( by separator: R ) -> SplitCollection> { split(by: RegexConsumer(separator)) } - public func splitFromBack( + func splitFromBack( by separator: R ) -> ReversedSplitCollection> { splitFromBack(by: RegexConsumer(separator)) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift index 75c6e1133..346094f9e 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift @@ -12,7 +12,7 @@ // MARK: `CollectionConsumer` algorithms extension Collection { - public func starts(with consumer: C) -> Bool + func starts(with consumer: C) -> Bool where C.Consumed == SubSequence { consumer.consuming(self[...]) != nil @@ -20,7 +20,7 @@ extension Collection { } extension BidirectionalCollection { - public func ends(with consumer: C) -> Bool + func ends(with consumer: C) -> Bool where C.Consumed == SubSequence { consumer.consumingBack(self[...]) != nil @@ -30,7 +30,7 @@ extension BidirectionalCollection { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { - public func starts(with prefix: C) -> Bool + func starts(with prefix: C) -> Bool where C.Element == Element { starts(with: FixedPatternConsumer(pattern: prefix)) @@ -38,7 +38,7 @@ extension Collection where Element: Equatable { } extension BidirectionalCollection where Element: Equatable { - public func ends(with suffix: C) -> Bool + func ends(with suffix: C) -> Bool where C.Element == Element { ends(with: FixedPatternConsumer(pattern: suffix)) @@ -48,11 +48,16 @@ extension BidirectionalCollection where Element: Equatable { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { + /// Returns a Boolean value indicating whether the initial elements of the + /// sequence are the same as the elements in the specified regex. + /// - Parameter regex: A regex to compare to this sequence. + /// - Returns: `true` if the initial elements of the sequence matches the + /// beginning of `regex`; otherwise, `false`. public func starts(with regex: R) -> Bool { starts(with: RegexConsumer(regex)) } - public func ends(with regex: R) -> Bool { + func ends(with regex: R) -> Bool { ends(with: RegexConsumer(regex)) } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift index 65a71e1b7..ed7cd7bc4 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift @@ -12,7 +12,7 @@ // MARK: `CollectionConsumer` algorithms extension Collection { - public func trimmingPrefix( + func trimmingPrefix( _ consumer: Consumer ) -> SubSequence where Consumer.Consumed == Self { let start = consumer.consuming(self) ?? startIndex @@ -21,7 +21,7 @@ extension Collection { } extension Collection where SubSequence == Self { - public mutating func trimPrefix( + mutating func trimPrefix( _ consumer: Consumer ) where Consumer.Consumed == Self { _ = consumer.consume(&self) @@ -32,7 +32,7 @@ extension RangeReplaceableCollection { // NOTE: Disfavored because the `Collection with SubSequence == Self` overload // should be preferred whenever both are available @_disfavoredOverload - public mutating func trimPrefix( + mutating func trimPrefix( _ consumer: Consumer ) where Consumer.Consumed == Self { if let start = consumer.consuming(self) { @@ -42,7 +42,7 @@ extension RangeReplaceableCollection { } extension BidirectionalCollection { - public func trimmingSuffix( + func trimmingSuffix( _ consumer: Consumer ) -> SubSequence where Consumer.Consumed == Self @@ -51,7 +51,7 @@ extension BidirectionalCollection { return self[..( + func trimming( _ consumer: Consumer ) -> SubSequence where Consumer.Consumed == Self { // NOTE: Might give different results than trimming the suffix before @@ -64,7 +64,7 @@ extension BidirectionalCollection { } extension BidirectionalCollection where SubSequence == Self { - public mutating func trimSuffix( + mutating func trimSuffix( _ consumer: Consumer ) where Consumer.Consumed == SubSequence { @@ -81,7 +81,7 @@ extension BidirectionalCollection where SubSequence == Self { extension RangeReplaceableCollection where Self: BidirectionalCollection { @_disfavoredOverload - public mutating func trimSuffix( + mutating func trimSuffix( _ consumer: Consumer ) where Consumer.Consumed == Self { @@ -103,7 +103,7 @@ extension RangeReplaceableCollection where Self: BidirectionalCollection { extension Collection { // TODO: Non-escaping and throwing - public func trimmingPrefix( + func trimmingPrefix( while predicate: @escaping (Element) -> Bool ) -> SubSequence { trimmingPrefix(ManyConsumer(base: PredicateConsumer(predicate: predicate))) @@ -129,13 +129,13 @@ extension RangeReplaceableCollection { } extension BidirectionalCollection { - public func trimmingSuffix( + func trimmingSuffix( while predicate: @escaping (Element) -> Bool ) -> SubSequence { trimmingSuffix(ManyConsumer(base: PredicateConsumer(predicate: predicate))) } - public func trimming( + func trimming( while predicate: @escaping (Element) -> Bool ) -> SubSequence { trimming(ManyConsumer(base: PredicateConsumer(predicate: predicate))) @@ -143,14 +143,14 @@ extension BidirectionalCollection { } extension BidirectionalCollection where SubSequence == Self { - public mutating func trimSuffix( + mutating func trimSuffix( while predicate: @escaping (Element) -> Bool ) { trimSuffix(ManyConsumer( base: PredicateConsumer(predicate: predicate))) } - public mutating func trim(while predicate: @escaping (Element) -> Bool) { + mutating func trim(while predicate: @escaping (Element) -> Bool) { let consumer = ManyConsumer( base: PredicateConsumer(predicate: predicate)) trimPrefix(consumer) @@ -160,14 +160,14 @@ extension BidirectionalCollection where SubSequence == Self { extension RangeReplaceableCollection where Self: BidirectionalCollection { @_disfavoredOverload - public mutating func trimSuffix( + mutating func trimSuffix( while predicate: @escaping (Element) -> Bool ) { trimSuffix(ManyConsumer(base: PredicateConsumer(predicate: predicate))) } @_disfavoredOverload - public mutating func trim(while predicate: @escaping (Element) -> Bool) { + mutating func trim(while predicate: @escaping (Element) -> Bool) { let consumer = ManyConsumer( base: PredicateConsumer(predicate: predicate)) trimPrefix(consumer) @@ -178,6 +178,13 @@ extension RangeReplaceableCollection where Self: BidirectionalCollection { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { + /// Returns a new collection of the same type by removing initial elements + /// that satisfy the given predicate from the start. + /// - Parameter predicate: A closure that takes an element of the sequence + /// as its argument and returns a Boolean value indicating whether the + /// element should be removed from the collection. + /// - Returns: A collection containing the elements of the collection that are + /// not removed by `predicate`. public func trimmingPrefix( _ prefix: Prefix ) -> SubSequence where Prefix.Element == Element { @@ -186,6 +193,11 @@ extension Collection where Element: Equatable { } extension Collection where SubSequence == Self, Element: Equatable { + /// Removes the initial elements that satisfy the given predicate from the + /// start of the sequence. + /// - Parameter predicate: A closure that takes an element of the sequence + /// as its argument and returns a Boolean value indicating whether the + /// element should be removed from the collection. public mutating func trimPrefix( _ prefix: Prefix ) where Prefix.Element == Element { @@ -195,6 +207,11 @@ extension Collection where SubSequence == Self, Element: Equatable { extension RangeReplaceableCollection where Element: Equatable { @_disfavoredOverload + /// Removes the initial elements that satisfy the given predicate from the + /// start of the sequence. + /// - Parameter predicate: A closure that takes an element of the sequence + /// as its argument and returns a Boolean value indicating whether the + /// element should be removed from the collection. public mutating func trimPrefix( _ prefix: Prefix ) where Prefix.Element == Element { @@ -203,13 +220,13 @@ extension RangeReplaceableCollection where Element: Equatable { } extension BidirectionalCollection where Element: Equatable { - public func trimmingSuffix( + func trimmingSuffix( _ suffix: Suffix ) -> SubSequence where Suffix.Element == Element { trimmingSuffix(FixedPatternConsumer(pattern: suffix)) } - public func trimming( + func trimming( _ pattern: Pattern ) -> SubSequence where Pattern.Element == Element { trimming(FixedPatternConsumer(pattern: pattern)) @@ -219,13 +236,13 @@ extension BidirectionalCollection where Element: Equatable { extension BidirectionalCollection where SubSequence == Self, Element: Equatable { - public mutating func trimSuffix( + mutating func trimSuffix( _ suffix: Suffix ) where Suffix.Element == Element { trimSuffix(FixedPatternConsumer(pattern: suffix)) } - public mutating func trim( + mutating func trim( _ pattern: Pattern ) where Pattern.Element == Element { let consumer = FixedPatternConsumer(pattern: pattern) @@ -238,14 +255,14 @@ extension RangeReplaceableCollection where Self: BidirectionalCollection, Element: Equatable { @_disfavoredOverload - public mutating func trimSuffix( + mutating func trimSuffix( _ prefix: Suffix ) where Suffix.Element == Element { trimSuffix(FixedPatternConsumer(pattern: prefix)) } @_disfavoredOverload - public mutating func trim( + mutating func trim( _ pattern: Pattern ) where Pattern.Element == Element { let consumer = FixedPatternConsumer(pattern: pattern) @@ -257,15 +274,20 @@ extension RangeReplaceableCollection // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { + /// Returns a new collection of the same type by removing `prefix` from the + /// start. + /// - Parameter prefix: The collection to remove from this collection. + /// - Returns: A collection containing the elements that does not match + /// `prefix` from the start. public func trimmingPrefix(_ regex: R) -> SubSequence { trimmingPrefix(RegexConsumer(regex)) } - public func trimmingSuffix(_ regex: R) -> SubSequence { + func trimmingSuffix(_ regex: R) -> SubSequence { trimmingSuffix(RegexConsumer(regex)) } - public func trimming(_ regex: R) -> SubSequence { + func trimming(_ regex: R) -> SubSequence { trimming(RegexConsumer(regex)) } } @@ -273,15 +295,17 @@ extension BidirectionalCollection where SubSequence == Substring { extension RangeReplaceableCollection where Self: BidirectionalCollection, SubSequence == Substring { + /// Removes the initial elements that matches the given regex. + /// - Parameter regex: The regex to remove from this collection. public mutating func trimPrefix(_ regex: R) { trimPrefix(RegexConsumer(regex)) } - public mutating func trimSuffix(_ regex: R) { + mutating func trimSuffix(_ regex: R) { trimSuffix(RegexConsumer(regex)) } - public mutating func trim(_ regex: R) { + mutating func trim(_ regex: R) { let consumer = RegexConsumer(regex) trimPrefix(consumer) trimSuffix(consumer) @@ -289,15 +313,15 @@ extension RangeReplaceableCollection } extension Substring { - public mutating func trimPrefix(_ regex: R) { + mutating func trimPrefix(_ regex: R) { trimPrefix(RegexConsumer(regex)) } - public mutating func trimSuffix(_ regex: R) { + mutating func trimSuffix(_ regex: R) { trimSuffix(RegexConsumer(regex)) } - public mutating func trim(_ regex: R) { + mutating func trim(_ regex: R) { let consumer = RegexConsumer(regex) trimPrefix(consumer) trimSuffix(consumer) diff --git a/Sources/_StringProcessing/Algorithms/Consumers/CollectionConsumer.swift b/Sources/_StringProcessing/Algorithms/Consumers/CollectionConsumer.swift index 95f772d7b..b71af470e 100644 --- a/Sources/_StringProcessing/Algorithms/Consumers/CollectionConsumer.swift +++ b/Sources/_StringProcessing/Algorithms/Consumers/CollectionConsumer.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -public protocol CollectionConsumer { +protocol CollectionConsumer { associatedtype Consumed: Collection func consuming( _ consumed: Consumed, @@ -18,13 +18,13 @@ public protocol CollectionConsumer { } extension CollectionConsumer { - public func consuming(_ consumed: Consumed) -> Consumed.Index? { + func consuming(_ consumed: Consumed) -> Consumed.Index? { consuming(consumed, in: consumed.startIndex.. Bool + func consume(_ consumed: inout Consumed) -> Bool where Consumed.SubSequence == Consumed { guard let index = consuming(consumed) else { return false } @@ -35,7 +35,7 @@ extension CollectionConsumer { // MARK: Consuming from the back -public protocol BidirectionalCollectionConsumer: CollectionConsumer +protocol BidirectionalCollectionConsumer: CollectionConsumer where Consumed: BidirectionalCollection { func consumingBack( @@ -45,11 +45,11 @@ public protocol BidirectionalCollectionConsumer: CollectionConsumer } extension BidirectionalCollectionConsumer { - public func consumingBack(_ consumed: Consumed) -> Consumed.Index? { + func consumingBack(_ consumed: Consumed) -> Consumed.Index? { consumingBack(consumed, in: consumed.startIndex.. Bool + func consumeBack(_ consumed: inout Consumed) -> Bool where Consumed.SubSequence == Consumed { guard let index = consumingBack(consumed) else { return false } diff --git a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift index c0699b805..2aea0f342 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift @@ -12,7 +12,7 @@ // MARK: `CollectionSearcher` algorithms extension Collection { - public func firstMatch( + func firstMatch( of searcher: S ) -> _MatchResult? where S.Searched == Self { var state = searcher.state(for: self, in: startIndex..( + func lastMatch( of searcher: S ) -> _BackwardMatchResult? where S.BackwardSearched == Self @@ -38,15 +38,26 @@ extension BidirectionalCollection { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func firstMatch( + func firstMatch( of regex: R ) -> _MatchResult>? { firstMatch(of: RegexConsumer(regex)) } - public func lastMatch( + func lastMatch( of regex: R ) -> _BackwardMatchResult>? { lastMatch(of: RegexConsumer(regex)) } + + /// Returns the first match of the specified regex within the collection. + /// - Parameter regex: The regex to search for. + /// - Returns: The first match of `regex` in the collection, or `nil` if + /// there isn't a match. + public func firstMatch( + of regex: R + ) -> Regex.Match? { + let slice = self[...] + return try? regex.firstMatch(in: slice.base) + } } diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift index f99e525b5..74ab48839 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift @@ -12,7 +12,7 @@ // MARK: `MatchingCollectionSearcher` algorithms extension RangeReplaceableCollection { - public func replacing< + func replacing< Searcher: MatchingCollectionSearcher, Replacement: Collection >( _ searcher: Searcher, @@ -40,7 +40,7 @@ extension RangeReplaceableCollection { return result } - public func replacing< + func replacing< Searcher: MatchingCollectionSearcher, Replacement: Collection >( _ searcher: Searcher, @@ -56,7 +56,7 @@ extension RangeReplaceableCollection { maxReplacements: maxReplacements) } - public mutating func replace< + mutating func replace< Searcher: MatchingCollectionSearcher, Replacement: Collection >( _ searcher: Searcher, @@ -75,7 +75,7 @@ extension RangeReplaceableCollection { // MARK: Regex algorithms extension RangeReplaceableCollection where SubSequence == Substring { - public func replacing( + func replacing( _ regex: R, with replacement: (_MatchResult>) throws -> Replacement, subrange: Range, @@ -88,7 +88,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: maxReplacements) } - public func replacing( + func replacing( _ regex: R, with replacement: (_MatchResult>) throws -> Replacement, maxReplacements: Int = .max @@ -100,7 +100,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: maxReplacements) } - public mutating func replace( + mutating func replace( _ regex: R, with replacement: (_MatchResult>) throws -> Replacement, maxReplacements: Int = .max @@ -110,4 +110,82 @@ extension RangeReplaceableCollection where SubSequence == Substring { with: replacement, maxReplacements: maxReplacements) } + + /// Returns a new collection in which all occurrences of a sequence matching + /// the given regex are replaced by another regex match. + /// - Parameters: + /// - regex: A regex describing the sequence to replace. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. + /// - subrange: The range in the collection in which to search for `regex`. + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - Returns: A new collection in which all occurrences of subsequence + /// matching `regex` are replaced by `replacement`. + public func replacing( + _ regex: R, + with replacement: (Regex.Match) throws -> Replacement, + subrange: Range, + maxReplacements: Int = .max + ) rethrows -> Self where Replacement.Element == Element { + + precondition(maxReplacements >= 0) + + var index = subrange.lowerBound + var result = Self() + result.append(contentsOf: self[..( + _ regex: R, + with replacement: (Regex.Match) throws -> Replacement, + maxReplacements: Int = .max + ) rethrows -> Self where Replacement.Element == Element { + try replacing( + regex, + with: replacement, + subrange: startIndex..( + _ regex: R, + with replacement: (Regex.Match) throws -> Replacement, + maxReplacements: Int = .max + ) rethrows where Replacement.Element == Element { + self = try replacing( + regex, + with: replacement, + subrange: startIndex.. { - public let match: S.Searched.SubSequence - public let result: S.Match +struct _MatchResult { + let match: S.Searched.SubSequence + let result: S.Match - public var range: Range { + var range: Range { match.startIndex.. { - public let match: S.BackwardSearched.SubSequence - public let result: S.Match +struct _BackwardMatchResult { + let match: S.BackwardSearched.SubSequence + let result: S.Match - public var range: Range { + var range: Range { match.startIndex.. { +struct MatchesCollection { public typealias Base = Searcher.Searched let base: Base @@ -33,7 +33,7 @@ public struct MatchesCollection { } } -public struct MatchesIterator< +struct MatchesIterator< Searcher: MatchingCollectionSearcher >: IteratorProtocol { public typealias Base = Searcher.Searched @@ -64,7 +64,7 @@ extension MatchesCollection: Sequence { extension MatchesCollection: Collection { // TODO: Custom `SubSequence` for the sake of more efficient slice iteration - public struct Index { + struct Index { var match: (range: Range, match: Searcher.Match)? var state: Searcher.State } @@ -122,7 +122,7 @@ extension MatchesCollection.Index: Comparable { // MARK: `ReversedMatchesCollection` // TODO: reversed matches -public struct ReversedMatchesCollection< +struct ReversedMatchesCollection< Searcher: BackwardMatchingCollectionSearcher > { public typealias Base = Searcher.BackwardSearched @@ -137,7 +137,7 @@ public struct ReversedMatchesCollection< } extension ReversedMatchesCollection: Sequence { - public struct Iterator: IteratorProtocol { + struct Iterator: IteratorProtocol { let base: Base let searcher: Searcher var state: Searcher.BackwardState @@ -166,7 +166,7 @@ extension ReversedMatchesCollection: Sequence { // MARK: `CollectionSearcher` algorithms extension Collection { - public func matches( + func matches( of searcher: S ) -> MatchesCollection where S.Searched == Self { MatchesCollection(base: self, searcher: searcher) @@ -174,7 +174,7 @@ extension Collection { } extension BidirectionalCollection { - public func matchesFromBack( + func matchesFromBack( of searcher: S ) -> ReversedMatchesCollection where S.BackwardSearched == Self { ReversedMatchesCollection(base: self, searcher: searcher) @@ -184,15 +184,38 @@ extension BidirectionalCollection { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func matches( + // FIXME: Replace `MatchesCollection` when SE-0346 is enabled + /// Returns a collection containing all matches of the specified regex. + /// - Parameter regex: The regex to search for. + /// - Returns: A collection of matches of `regex`. + func matches( of regex: R ) -> MatchesCollection> { matches(of: RegexConsumer(regex)) } - - public func matchesFromBack( + + func matchesFromBack( of regex: R ) -> ReversedMatchesCollection> { matchesFromBack(of: RegexConsumer(regex)) } + + // FIXME: Replace the returned value as `some Collection.Match> + // when SE-0346 is enabled + func _matches(of regex: R) -> [Regex.Match] { + let slice = self[...] + var start = self.startIndex + let end = self.endIndex + + var result = [Regex.Match]() + while start < end { + guard let match = try? regex._firstMatch(slice.base, in: start.. ) -> Consumed.Index? { @@ -28,7 +28,7 @@ extension MatchingCollectionConsumer { // MARK: Consuming from the back -public protocol BidirectionalMatchingCollectionConsumer: +protocol BidirectionalMatchingCollectionConsumer: MatchingCollectionConsumer, BidirectionalCollectionConsumer { func matchingConsumingBack( @@ -38,7 +38,7 @@ public protocol BidirectionalMatchingCollectionConsumer: } extension BidirectionalMatchingCollectionConsumer { - public func consumingBack( + func consumingBack( _ consumed: Consumed, in range: Range ) -> Consumed.Index? { diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchingCollectionSearcher.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchingCollectionSearcher.swift index eadb46f9e..902d94591 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/MatchingCollectionSearcher.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/MatchingCollectionSearcher.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -public protocol MatchingCollectionSearcher: CollectionSearcher { +protocol MatchingCollectionSearcher: CollectionSearcher { associatedtype Match func matchingSearch( _ searched: Searched, @@ -18,7 +18,7 @@ public protocol MatchingCollectionSearcher: CollectionSearcher { } extension MatchingCollectionSearcher { - public func search( + func search( _ searched: Searched, _ state: inout State ) -> Range? { @@ -26,7 +26,7 @@ extension MatchingCollectionSearcher { } } -public protocol MatchingStatelessCollectionSearcher: +protocol MatchingStatelessCollectionSearcher: MatchingCollectionSearcher, StatelessCollectionSearcher { func matchingSearch( @@ -38,14 +38,14 @@ public protocol MatchingStatelessCollectionSearcher: extension MatchingStatelessCollectionSearcher { // for disambiguation between the `MatchingCollectionSearcher` and // `StatelessCollectionSearcher` overloads - public func search( + func search( _ searched: Searched, _ state: inout State ) -> Range? { matchingSearch(searched, &state)?.range } - public func matchingSearch( + func matchingSearch( _ searched: Searched, _ state: inout State ) -> (range: Range, match: Match)? { @@ -69,7 +69,7 @@ extension MatchingStatelessCollectionSearcher { return (range, value) } - public func search( + func search( _ searched: Searched, in range: Range ) -> Range? { @@ -79,7 +79,7 @@ extension MatchingStatelessCollectionSearcher { // MARK: Searching from the back -public protocol BackwardMatchingCollectionSearcher: BackwardCollectionSearcher { +protocol BackwardMatchingCollectionSearcher: BackwardCollectionSearcher { associatedtype Match func matchingSearchBack( _ searched: BackwardSearched, @@ -87,7 +87,7 @@ public protocol BackwardMatchingCollectionSearcher: BackwardCollectionSearcher { ) -> (range: Range, match: Match)? } -public protocol BackwardMatchingStatelessCollectionSearcher: +protocol BackwardMatchingStatelessCollectionSearcher: BackwardMatchingCollectionSearcher, BackwardStatelessCollectionSearcher { func matchingSearchBack( @@ -97,14 +97,14 @@ public protocol BackwardMatchingStatelessCollectionSearcher: } extension BackwardMatchingStatelessCollectionSearcher { - public func searchBack( + func searchBack( _ searched: BackwardSearched, in range: Range ) -> Range? { matchingSearchBack(searched, in: range)?.range } - public func matchingSearchBack( + func matchingSearchBack( _ searched: BackwardSearched, _ state: inout BackwardState) -> (range: Range, match: Match)? { diff --git a/Sources/_StringProcessing/Algorithms/Searchers/CollectionSearcher.swift b/Sources/_StringProcessing/Algorithms/Searchers/CollectionSearcher.swift index 78e4fc925..5eb199086 100644 --- a/Sources/_StringProcessing/Algorithms/Searchers/CollectionSearcher.swift +++ b/Sources/_StringProcessing/Algorithms/Searchers/CollectionSearcher.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -public struct DefaultSearcherState { +struct DefaultSearcherState { enum Position { case index(Searched.Index) case done @@ -19,7 +19,7 @@ public struct DefaultSearcherState { let end: Searched.Index } -public protocol CollectionSearcher { +protocol CollectionSearcher { associatedtype Searched: Collection associatedtype State @@ -30,7 +30,7 @@ public protocol CollectionSearcher { ) -> Range? } -public protocol StatelessCollectionSearcher: CollectionSearcher +protocol StatelessCollectionSearcher: CollectionSearcher where State == DefaultSearcherState { func search( @@ -39,14 +39,14 @@ public protocol StatelessCollectionSearcher: CollectionSearcher } extension StatelessCollectionSearcher { - public func state( + func state( for searched: Searched, in range: Range ) -> State { State(position: .index(range.lowerBound), end: range.upperBound) } - public func search( + func search( _ searched: Searched, _ state: inout State ) -> Range? { @@ -71,7 +71,7 @@ extension StatelessCollectionSearcher { // MARK: Searching from the back -public protocol BackwardCollectionSearcher { +protocol BackwardCollectionSearcher { associatedtype BackwardSearched: BidirectionalCollection associatedtype BackwardState @@ -84,7 +84,7 @@ public protocol BackwardCollectionSearcher { ) -> Range? } -public protocol BackwardStatelessCollectionSearcher: BackwardCollectionSearcher +protocol BackwardStatelessCollectionSearcher: BackwardCollectionSearcher where BackwardState == DefaultSearcherState { func searchBack( @@ -94,14 +94,14 @@ public protocol BackwardStatelessCollectionSearcher: BackwardCollectionSearcher } extension BackwardStatelessCollectionSearcher { - public func backwardState( + func backwardState( for searched: BackwardSearched, in range: Range ) -> BackwardState { BackwardState(position: .index(range.upperBound), end: range.lowerBound) } - public func searchBack( + func searchBack( _ searched: BackwardSearched, _ state: inout BackwardState) -> Range? { guard diff --git a/Sources/_StringProcessing/Algorithms/Searchers/PatternOrEmpty.swift b/Sources/_StringProcessing/Algorithms/Searchers/PatternOrEmpty.swift index ee1b04adf..3b3fe22f9 100644 --- a/Sources/_StringProcessing/Algorithms/Searchers/PatternOrEmpty.swift +++ b/Sources/_StringProcessing/Algorithms/Searchers/PatternOrEmpty.swift @@ -10,14 +10,14 @@ //===----------------------------------------------------------------------===// /// Wraps a searcher that searches for a given pattern. If the pattern is empty, falls back on matching every empty index range exactly once. -public struct PatternOrEmpty { +struct PatternOrEmpty { let searcher: Searcher? } extension PatternOrEmpty: CollectionSearcher { - public typealias Searched = Searcher.Searched + typealias Searched = Searcher.Searched - public struct State { + struct State { enum Representation { case state(Searcher.State) case empty(index: Searched.Index, end: Searched.Index) @@ -27,7 +27,7 @@ extension PatternOrEmpty: CollectionSearcher { let representation: Representation } - public func state( + func state( for searched: Searcher.Searched, in range: Range ) -> State { @@ -40,7 +40,7 @@ extension PatternOrEmpty: CollectionSearcher { } } - public func search( + func search( _ searched: Searched, _ state: inout State ) -> Range? { diff --git a/Tests/RegexBuilderTests/AlgorithmsTests.swift b/Tests/RegexBuilderTests/AlgorithmsTests.swift index 183d247a7..7625af385 100644 --- a/Tests/RegexBuilderTests/AlgorithmsTests.swift +++ b/Tests/RegexBuilderTests/AlgorithmsTests.swift @@ -14,18 +14,20 @@ import _StringProcessing @testable import RegexBuilder class RegexConsumerTests: XCTestCase { - func testMatches() { - let regex = Capture(OneOrMore(.digit)) { 2 * Int($0)! } - let str = "foo 160 bar 99 baz" - XCTAssertEqual(str.matches(of: regex).map(\.result.1), [320, 198]) - } + // FIXME: enable this test when we update the return type of `matches(of:)` + // when SE-0346 is available + // func testMatches() { + // let regex = Capture(OneOrMore(.digit)) { 2 * Int($0)! } + // let str = "foo 160 bar 99 baz" + // XCTAssertEqual(str.matches(of: regex).map(\.result.1), [320, 198]) + // } func testMatchReplace() { func replaceTest( _ regex: R, input: String, result: String, - _ replace: (_MatchResult>) -> String, + _ replace: (Regex.Match) -> String, file: StaticString = #file, line: UInt = #line ) { @@ -38,13 +40,13 @@ class RegexConsumerTests: XCTestCase { int, input: "foo 160 bar 99 baz", result: "foo 240 bar 143 baz", - { match in String(match.result.1, radix: 8) }) + { match in String(match.output.1, radix: 8) }) replaceTest( Regex { int; "+"; int }, input: "9+16, 0+3, 5+5, 99+1", result: "25, 3, 10, 100", - { match in "\(match.result.1 + match.result.2)" }) + { match in "\(match.output.1 + match.output.2)" }) // TODO: Need to support capture history // replaceTest( @@ -57,6 +59,6 @@ class RegexConsumerTests: XCTestCase { Regex { int; "x"; int; Optionally { "x"; int } }, input: "2x3 5x4x3 6x0 1x2x3x4", result: "6 60 0 6x4", - { match in "\(match.result.1 * match.result.2 * (match.result.3 ?? 1))" }) + { match in "\(match.output.1 * match.output.2 * (match.output.3 ?? 1))" }) } } diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index 7be95c28c..19c4a3896 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -64,7 +64,7 @@ func customTest( case .match: result = input.matchWhole(regex)?.output case .firstMatch: - result = input.firstMatch(of: regex)?.result + result = input.firstMatch(of: regex)?.output } XCTAssertEqual(result, match) } @@ -120,9 +120,9 @@ class CustomRegexComponentTests: XCTestCase { return } - XCTAssertEqual(res3.match, "123") - XCTAssertEqual(res3.result.0, "123") - XCTAssertEqual(res3.result.1, "123") + XCTAssertEqual(res3.range, "ab123c".index(atOffset: 2)..<"ab123c".index(atOffset: 5)) + XCTAssertEqual(res3.output.0, "123") + XCTAssertEqual(res3.output.1, "123") let regex4 = Regex { OneOrMore { @@ -135,7 +135,7 @@ class CustomRegexComponentTests: XCTestCase { return } - XCTAssertEqual(res4.result.0, "123") - XCTAssertEqual(res4.result.1, 3) + XCTAssertEqual(res4.output.0, "123") + XCTAssertEqual(res4.output.1, 3) } } diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 50358734d..2762eeb79 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -704,10 +704,10 @@ class RegexDSLTests: XCTestCase { else { return nil } let result = SemanticVersion( - major: match.result.1, - minor: match.result.2, - patch: match.result.3 ?? 0, - dev: match.result.4.map(String.init)) + major: match.output.1, + minor: match.output.2, + patch: match.output.3 ?? 0, + dev: match.output.4.map(String.init)) return (match.range.upperBound, result) } } From 3b77fe44732449bff04c0ef58fa58c8822c87bdb Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 7 Apr 2022 15:12:27 -0500 Subject: [PATCH 039/133] Fill out remainder of options API (#246) This adds methods to RegexComponent for the remainder of the regex options, and passes the current MatchingOptions further down into the consumers so that the correct behavior can be used. --- Sources/_StringProcessing/ByteCodeGen.swift | 31 ++-- .../_StringProcessing/CharacterClass.swift | 74 +++++--- .../_StringProcessing/ConsumerInterface.swift | 2 +- .../_StringProcessing/MatchingOptions.swift | 27 ++- Sources/_StringProcessing/Regex/Options.swift | 164 +++++++++++++++++- Tests/RegexBuilderTests/RegexDSLTests.swift | 54 +++--- Tests/RegexTests/MatchTests.swift | 99 ++++++++++- 7 files changed, 379 insertions(+), 72 deletions(-) diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index d03a1e382..d6d6c3c5e 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -111,30 +111,41 @@ extension Compiler.ByteCodeGen { } case .startOfLine: - builder.buildAssert { (input, pos, bounds) in - pos == input.startIndex || - input[input.index(before: pos)].isNewline + if options.anchorsMatchNewlines { + builder.buildAssert { (input, pos, bounds) in + pos == input.startIndex || input[input.index(before: pos)].isNewline + } + } else { + builder.buildAssert { (input, pos, bounds) in + pos == input.startIndex + } } - + case .endOfLine: - builder.buildAssert { (input, pos, bounds) in - pos == input.endIndex || input[pos].isNewline + if options.anchorsMatchNewlines { + builder.buildAssert { (input, pos, bounds) in + pos == input.endIndex || input[pos].isNewline + } + } else { + builder.buildAssert { (input, pos, bounds) in + pos == input.endIndex + } } case .wordBoundary: // TODO: May want to consider Unicode level - builder.buildAssert { (input, pos, bounds) in + builder.buildAssert { [options] (input, pos, bounds) in // TODO: How should we handle bounds? CharacterClass.word.isBoundary( - input, at: pos, bounds: bounds) + input, at: pos, bounds: bounds, with: options) } case .notWordBoundary: // TODO: May want to consider Unicode level - builder.buildAssert { (input, pos, bounds) in + builder.buildAssert { [options] (input, pos, bounds) in // TODO: How should we handle bounds? !CharacterClass.word.isBoundary( - input, at: pos, bounds: bounds) + input, at: pos, bounds: bounds, with: options) } } } diff --git a/Sources/_StringProcessing/CharacterClass.swift b/Sources/_StringProcessing/CharacterClass.swift index d44fa9fb2..bdf34d0a7 100644 --- a/Sources/_StringProcessing/CharacterClass.swift +++ b/Sources/_StringProcessing/CharacterClass.swift @@ -59,14 +59,14 @@ public struct CharacterClass: Hashable { var op: SetOperator var rhs: CharacterSetComponent - public func matches(_ c: Character) -> Bool { + public func matches(_ c: Character, with options: MatchingOptions) -> Bool { switch op { case .intersection: - return lhs.matches(c) && rhs.matches(c) + return lhs.matches(c, with: options) && rhs.matches(c, with: options) case .subtraction: - return lhs.matches(c) && !rhs.matches(c) + return lhs.matches(c, with: options) && !rhs.matches(c, with: options) case .symmetricDifference: - return lhs.matches(c) != rhs.matches(c) + return lhs.matches(c, with: options) != rhs.matches(c, with: options) } } } @@ -87,14 +87,28 @@ public struct CharacterClass: Hashable { .setOperation(.init(lhs: lhs, op: op, rhs: rhs)) } - public func matches(_ character: Character) -> Bool { + public func matches(_ character: Character, with options: MatchingOptions) -> Bool { switch self { - case .character(let c): return c == character - case .range(let range): return range.contains(character) + case .character(let c): + if options.isCaseInsensitive { + return c.lowercased() == character.lowercased() + } else { + return c == character + } + case .range(let range): + if options.isCaseInsensitive { + let newLower = range.lowerBound.lowercased() + let newUpper = range.upperBound.lowercased() + // FIXME: Is failing this possible? Is this the right behavior if so? + guard newLower <= newUpper else { return false } + return (newLower...newUpper).contains(character.lowercased()) + } else { + return range.contains(character) + } case .characterClass(let custom): let str = String(character) - return custom.matches(in: str, at: str.startIndex) != nil - case .setOperation(let op): return op.matches(character) + return custom.matches(in: str, at: str.startIndex, with: options) != nil + case .setOperation(let op): return op.matches(character, with: options) } } } @@ -135,21 +149,26 @@ public struct CharacterClass: Hashable { /// Returns the end of the match of this character class in `str`, if /// it matches. - public func matches(in str: String, at i: String.Index) -> String.Index? { + public func matches(in str: String, at i: String.Index, with options: MatchingOptions) -> String.Index? { switch matchLevel { case .graphemeCluster: let c = str[i] var matched: Bool switch cc { case .any, .anyGrapheme: matched = true - case .digit: matched = c.isNumber - case .hexDigit: matched = c.isHexDigit + case .digit: + matched = c.isNumber && (c.isASCII || !options.usesASCIIDigits) + case .hexDigit: + matched = c.isHexDigit && (c.isASCII || !options.usesASCIIDigits) case .horizontalWhitespace: fatalError("Not implemented") - case .newlineSequence: matched = c.isNewline + case .newlineSequence: + matched = c.isNewline && (c.isASCII || !options.usesASCIISpaces) case .verticalWhitespace: fatalError("Not implemented") - case .whitespace: matched = c.isWhitespace - case .word: matched = c.isWordCharacter - case .custom(let set): matched = set.any { $0.matches(c) } + case .whitespace: + matched = c.isWhitespace && (c.isASCII || !options.usesASCIISpaces) + case .word: + matched = c.isWordCharacter && (c.isASCII || !options.usesASCIIWord) + case .custom(let set): matched = set.any { $0.matches(c, with: options) } } if isInverted { matched.toggle() @@ -161,13 +180,17 @@ public struct CharacterClass: Hashable { switch cc { case .any: matched = true case .anyGrapheme: fatalError("Not matched in this mode") - case .digit: matched = c.properties.numericType != nil - case .hexDigit: matched = Character(c).isHexDigit + case .digit: + matched = c.properties.numericType != nil && (c.isASCII || !options.usesASCIIDigits) + case .hexDigit: + matched = Character(c).isHexDigit && (c.isASCII || !options.usesASCIIDigits) case .horizontalWhitespace: fatalError("Not implemented") case .newlineSequence: fatalError("Not implemented") case .verticalWhitespace: fatalError("Not implemented") - case .whitespace: matched = c.properties.isWhitespace - case .word: matched = c.properties.isAlphabetic || c == "_" + case .whitespace: + matched = c.properties.isWhitespace && (c.isASCII || !options.usesASCIISpaces) + case .word: + matched = (c.properties.isAlphabetic || c == "_") && (c.isASCII || !options.usesASCIIWord) case .custom: fatalError("Not supported") } if isInverted { @@ -495,21 +518,22 @@ extension CharacterClass { func isBoundary( _ input: String, at pos: String.Index, - bounds: Range + bounds: Range, + with options: MatchingOptions ) -> Bool { // FIXME: How should we handle bounds? // We probably need two concepts if input.isEmpty { return false } if pos == input.startIndex { - return self.matches(in: input, at: pos) != nil + return self.matches(in: input, at: pos, with: options) != nil } let priorIdx = input.index(before: pos) if pos == input.endIndex { - return self.matches(in: input, at: priorIdx) != nil + return self.matches(in: input, at: priorIdx, with: options) != nil } - let prior = self.matches(in: input, at: priorIdx) != nil - let current = self.matches(in: input, at: pos) != nil + let prior = self.matches(in: input, at: priorIdx, with: options) != nil + let current = self.matches(in: input, at: pos, with: options) != nil return prior != current } diff --git a/Sources/_StringProcessing/ConsumerInterface.swift b/Sources/_StringProcessing/ConsumerInterface.swift index e372280f2..b343862ef 100644 --- a/Sources/_StringProcessing/ConsumerInterface.swift +++ b/Sources/_StringProcessing/ConsumerInterface.swift @@ -136,7 +136,7 @@ extension AST.Atom { ) { return { input, bounds in // FIXME: should we worry about out of bounds? - cc.matches(in: input, at: bounds.lowerBound) + cc.matches(in: input, at: bounds.lowerBound, with: opts) } } diff --git a/Sources/_StringProcessing/MatchingOptions.swift b/Sources/_StringProcessing/MatchingOptions.swift index 899891184..c4b2b8de7 100644 --- a/Sources/_StringProcessing/MatchingOptions.swift +++ b/Sources/_StringProcessing/MatchingOptions.swift @@ -13,7 +13,7 @@ import _RegexParser /// A type that represents the current state of regex matching options, with /// stack-based scoping. -struct MatchingOptions { +public struct MatchingOptions { fileprivate var stack: [Representation] fileprivate func _invariantCheck() { @@ -67,11 +67,32 @@ extension MatchingOptions { stack.last!.contains(.singleLine) } + var anchorsMatchNewlines: Bool { + stack.last!.contains(.multiline) + } + + var usesASCIIWord: Bool { + stack.last!.contains(.asciiOnlyWord) + || stack.last!.contains(.asciiOnlyPOSIXProps) + } + + var usesASCIIDigits: Bool { + stack.last!.contains(.asciiOnlyDigit) + || stack.last!.contains(.asciiOnlyPOSIXProps) + } + + var usesASCIISpaces: Bool { + stack.last!.contains(.asciiOnlySpace) + || stack.last!.contains(.asciiOnlyPOSIXProps) + } + + var usesSimpleUnicodeBoundaries: Bool { + !stack.last!.contains(.unicodeWordBoundaries) + } + enum SemanticLevel { case graphemeCluster case unicodeScalar - // TODO: include? - // case byte } var semanticLevel: SemanticLevel { diff --git a/Sources/_StringProcessing/Regex/Options.swift b/Sources/_StringProcessing/Regex/Options.swift index 04be79c6e..38fba02d6 100644 --- a/Sources/_StringProcessing/Regex/Options.swift +++ b/Sources/_StringProcessing/Regex/Options.swift @@ -12,17 +12,163 @@ import _RegexParser extension RegexComponent { - public func caseSensitive(_ isCaseSensitive: Bool) -> Regex { - // The API is "case sensitive = true or false", so as to avoid the - // double negatives inherent in setting "case insensitive" to a Boolean - // value. The internal version of this option, on the other hand, is - // `.caseInsensitive`, derived from the `(?i)` regex literal option. - let sequence = isCaseSensitive - ? AST.MatchingOptionSequence(removing: [.init(.caseInsensitive, location: .fake)]) - : AST.MatchingOptionSequence(adding: [.init(.caseInsensitive, location: .fake)]) + /// Returns a regular expression that ignores casing when matching. + public func ignoringCase(_ ignoreCase: Bool = true) -> Regex { + wrapInOption(.caseInsensitive, addingIf: ignoreCase) + } + + /// Returns a regular expression that only matches ASCII characters as "word + /// characters". + public func usingASCIIWordCharacters(_ useASCII: Bool = true) -> Regex { + wrapInOption(.asciiOnlyDigit, addingIf: useASCII) + } + + /// Returns a regular expression that only matches ASCII characters as digits. + public func usingASCIIDigits(_ useASCII: Bool = true) -> Regex { + wrapInOption(.asciiOnlyDigit, addingIf: useASCII) + } + + /// Returns a regular expression that only matches ASCII characters as space + /// characters. + public func usingASCIISpaces(_ useASCII: Bool = true) -> Regex { + wrapInOption(.asciiOnlySpace, addingIf: useASCII) + } + + /// Returns a regular expression that only matches ASCII characters when + /// matching character classes. + public func usingASCIICharacterClasses(_ useASCII: Bool = true) -> Regex { + wrapInOption(.asciiOnlyPOSIXProps, addingIf: useASCII) + } + + /// Returns a regular expression that uses the Unicode word boundary + /// algorithm. + /// + /// This option is enabled by default; pass `false` to disable use of + /// Unicode's word boundary algorithm. + public func usingUnicodeWordBoundaries(_ useUnicodeWordBoundaries: Bool = true) -> Regex { + wrapInOption(.unicodeWordBoundaries, addingIf: useUnicodeWordBoundaries) + } + + /// Returns a regular expression where the start and end of input + /// anchors (`^` and `$`) also match against the start and end of a line. + /// + /// - Parameter dotMatchesNewlines: A Boolean value indicating whether `.` + /// should match a newline character. + public func dotMatchesNewlines(_ dotMatchesNewlines: Bool = true) -> Regex { + wrapInOption(.singleLine, addingIf: dotMatchesNewlines) + } + + /// Returns a regular expression that matches with the specified semantic + /// level. + /// + /// When matching with grapheme cluster semantics (the default), + /// metacharacters like `.` and `\w`, custom character classes, and character + /// class instances like `.any` match a grapheme cluster when possible, + /// corresponding with the default string representation. In addition, + /// matching with grapheme cluster semantics compares characters using their + /// canonical representation, corresponding with how strings comparison works. + /// + /// When matching with Unicode scalar semantics, metacharacters and character + /// classes always match a single Unicode scalar value, even if that scalar + /// comprises part of a grapheme cluster. + /// + /// These semantic levels can lead to different results, especially when + /// working with strings that have decomposed characters. In the following + /// example, `queRegex` matches any 3-character string that begins with `"q"`. + /// + /// let composed = "qué" + /// let decomposed = "que\u{301}" + /// + /// let queRegex = /^q..$/ + /// + /// print(composed.contains(queRegex)) + /// // Prints "true" + /// print(decomposed.contains(queRegex)) + /// // Prints "true" + /// + /// When using Unicode scalar semantics, however, the regular expression only + /// matches the composed version of the string, because each `.` matches a + /// single Unicode scalar value. + /// + /// let queRegexScalar = queRegex.matchingSemantics(.unicodeScalar) + /// print(composed.contains(queRegexScalar)) + /// // Prints "true" + /// print(decomposed.contains(queRegexScalar)) + /// // Prints "false" + public func matchingSemantics(_ semanticLevel: RegexSemanticLevel) -> Regex { + switch semanticLevel.base { + case .graphemeCluster: + return wrapInOption(.graphemeClusterSemantics, addingIf: true) + case .unicodeScalar: + return wrapInOption(.unicodeScalarSemantics, addingIf: true) + } + } +} + +public struct RegexSemanticLevel: Hashable { + internal enum Representation { + case graphemeCluster + case unicodeScalar + } + + internal var base: Representation + + /// Match at the default semantic level of a string, where each matched + /// element is a `Character`. + public static var graphemeCluster: RegexSemanticLevel { + .init(base: .graphemeCluster) + } + + /// Match at the semantic level of a string's `UnicodeScalarView`, where each + /// matched element is a `UnicodeScalar` value. + public static var unicodeScalar: RegexSemanticLevel { + .init(base: .unicodeScalar) + } +} + +// Options that only affect literals +extension RegexComponent { + /// Returns a regular expression where the start and end of input + /// anchors (`^` and `$`) also match against the start and end of a line. + /// + /// This method corresponds to applying the `m` option in a regular + /// expression literal, and only applies to regular expressions specified as + /// literals. For this behavior in the `RegexBuilder` syntax, see + /// ``Anchor.startOfLine``, ``Anchor.endOfLine``, ``Anchor.startOfInput``, + /// and ``Anchor.endOfInput``. + /// + /// - Parameter matchLineEndings: A Boolean value indicating whether `^` and + /// `$` should match the start and end of lines, respectively. + public func anchorsMatchLineEndings(_ matchLineEndings: Bool = true) -> Regex { + wrapInOption(.multiline, addingIf: matchLineEndings) + } + + /// Returns a regular expression where quantifiers are reluctant by default + /// instead of eager. + /// + /// This method corresponds to applying the `U` option in a regular + /// expression literal, and only applies to regular expressions specified as + /// literals. In the `RegexBuilder` syntax, pass a ``QuantificationBehavior`` + /// value to any quantification method to change its behavior. + /// + /// - Parameter useReluctantCaptures: A Boolean value indicating whether + /// quantifiers should be reluctant by default. + public func reluctantCaptures(_ useReluctantCaptures: Bool = true) -> Regex { + wrapInOption(.reluctantByDefault, addingIf: useReluctantCaptures) + } +} + +// MARK: - Helper method +extension RegexComponent { + fileprivate func wrapInOption( + _ option: AST.MatchingOption.Kind, + addingIf shouldAdd: Bool) -> Regex + { + let sequence = shouldAdd + ? AST.MatchingOptionSequence(adding: [.init(option, location: .fake)]) + : AST.MatchingOptionSequence(removing: [.init(option, location: .fake)]) return Regex(node: .nonCapturingGroup( .changeMatchingOptions(sequence, isIsolated: false), regex.root)) } } - diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 2762eeb79..2044c8859 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -175,7 +175,7 @@ class RegexDSLTests: XCTestCase { matchType: Substring.self, ==) { OneOrMore { "abc" - }.caseSensitive(false) + }.ignoringCase(true) } // Multiple options on one component wrap successively, but do not @@ -189,8 +189,8 @@ class RegexDSLTests: XCTestCase { OneOrMore { "abc" } - .caseSensitive(false) - .caseSensitive(true) + .ignoringCase(true) + .ignoringCase(false) } // An option on an outer component doesn't override an option set on an @@ -204,10 +204,10 @@ class RegexDSLTests: XCTestCase { ("abcdeABCdeaBcde", "abcdeABCdeaBcde"), matchType: Substring.self, ==) { OneOrMore { - "abc".caseSensitive(false) + "abc".ignoringCase(true) Optionally("de") } - .caseSensitive(true) + .ignoringCase(false) } } @@ -216,32 +216,44 @@ class RegexDSLTests: XCTestCase { ("abc1def2", ("abc1def2", "2")), matchType: (Substring, Substring).self, ==) { - OneOrMore { - OneOrMore(.word) - Capture(.digit) - } + OneOrMore(.word) + Capture(.digit) + ZeroOrMore(.any) } try _testDSLCaptures( - ("abc1def2", ("abc1def2", "2")), + ("abc1def2", ("abc1def2", "1")), matchType: (Substring, Substring).self, ==) { - OneOrMore { - OneOrMore(.word, .reluctantly) - Capture(.digit) - } + OneOrMore(.word, .reluctantly) + Capture(.digit) + ZeroOrMore(.any) } - + +#if os(macOS) + try XCTExpectFailure("'relucantCaptures()' API should only affect regex literals") { + try _testDSLCaptures( + ("abc1def2", ("abc1def2", "2")), + matchType: (Substring, Substring).self, ==) + { + Regex { + OneOrMore(.word) + Capture(.digit) + ZeroOrMore(.any) + }.reluctantCaptures() + } + } +#endif + try _testDSLCaptures( - ("abc1def2", ("abc1def2", "2")), + ("abc1def2", ("abc1def2", "1")), matchType: (Substring, Substring).self, ==) { - OneOrMore { - OneOrMore(.reluctantly) { - .word - } - Capture(.digit) + OneOrMore(.reluctantly) { + .word } + Capture(.digit) + ZeroOrMore(.any) } try _testDSLCaptures( diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index 0ecbd5ad3..f1074c033 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -874,15 +874,15 @@ extension RegexTests { ("123", "123"), (" 123", nil), ("123 456", "123"), - (" 123 \n456", "456"), - (" \n123 \n456", "123")) + (" 123 \n456", nil), + (" \n123 \n456", nil)) firstMatchTests( #"\d+$"#, ("123", "123"), (" 123", "123"), (" 123 \n456", "456"), - (" 123\n456", "123"), + (" 123\n456", "456"), ("123 456", "456")) firstMatchTests( @@ -1202,6 +1202,89 @@ extension RegexTests { ("cafe", true), ("CaFe", true), ("EfAc", true)) + matchTest( + #"(?i)[a-f]{4}"#, + ("cafe", true), + ("CaFe", true), + ("EfAc", true)) + } + + func testASCIIClasses() { + // 'D' ASCII-only digits + matchTest( + #"\d+"#, + ("123", true), + ("¹೨¾", true)) + matchTest( + #"(?D)\d+"#, + ("123", true), + ("¹೨¾", false)) + matchTest( + #"(?P)\d+"#, + ("123", true), + ("¹೨¾", false)) + + // 'W' ASCII-only word characters (and word boundaries) + matchTest( + #"\w+"#, + ("aeiou", true), + ("åe\u{301}ïôú", true)) + matchTest( + #"(?W)\w+"#, + ("aeiou", true), + ("åe\u{301}ïôú", false)) + matchTest( + #"(?P)\w+"#, + ("aeiou", true), + ("åe\u{301}ïôú", false)) + + matchTest( + #"abcd\b.+"#, + ("abcd ef", true), + ("abcdef", false), + ("abcdéf", false)) + matchTest( + #"(?W)abcd\b.+"#, + ("abcd ef", true), + ("abcdef", false), + ("abcdéf", true)) // "dé" matches /d\b./ because "é" isn't ASCII + matchTest( + #"(?P)abcd\b.+"#, + ("abcd ef", true), + ("abcdef", false), + ("abcdéf", true)) // "dé" matches /d\b./ because "é" isn't ASCII + + // 'S' ASCII-only spaces + matchTest( + #"a\sb"#, + ("a\tb", true), + ("a\u{202f}b", true)) // NARROW NO-BREAK SPACE + matchTest( + #"(?S)a\sb"#, + ("a\tb", true), + ("a\u{202f}b", false)) + matchTest( + #"(?P)a\sb"#, + ("a\tb", true), + ("a\u{202f}b", false)) + } + + func testAnchorMatching() throws { + let string = """ + 01: Alabama + 02: Alaska + 03: Arizona + 04: Arkansas + 05: California + """ + XCTAssertTrue(string.contains(try Regex(compiling: #"^\d+"#))) + XCTAssertEqual(string.ranges(of: try Regex(compiling: #"^\d+"#)).count, 1) + XCTAssertEqual(string.ranges(of: try Regex(compiling: #"(?m)^\d+"#)).count, 5) + + let regex = try Regex(compiling: #"^\d+: [\w ]+$"#) + XCTAssertFalse(string.contains(regex)) + let allRanges = string.ranges(of: regex.anchorsMatchLineEndings()) + XCTAssertEqual(allRanges.count, 5) } func testMatchingOptionsScope() { @@ -1225,6 +1308,16 @@ extension RegexTests { firstMatchTest(#"(?s)((?-s)((?i)a)).b"#, input: "a\nb", match: "a\nb") } + func testOptionMethods() throws { + let regex = try Regex(compiling: "c.f.") + XCTAssertTrue ("cafe".contains(regex)) + XCTAssertFalse("CaFe".contains(regex)) + + let caseInsensitiveRegex = regex.ignoringCase() + XCTAssertTrue("cafe".contains(caseInsensitiveRegex)) + XCTAssertTrue("CaFe".contains(caseInsensitiveRegex)) + } + // MARK: Character Semantics var eComposed: String { "é" } From 93abfcb41680beec71a0c6e00d1f859944bf41bb Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 7 Apr 2022 21:24:25 -0500 Subject: [PATCH 040/133] Move `CharacterClass` API into RegexBuilder (#254) Makes the existing CharacterClass model type SPI, and adds a public CharacterClass type to the RegexBuilder module, which uses a DSLTree char class instead of the AST's version. RegexBuilder.CharacterClass is a more limited API than we need for the internal character class model, giving us room to expand on it as necessary in the future. --- Sources/RegexBuilder/CharacterClass.swift | 215 ++++++++++++++++++ Sources/_StringProcessing/ByteCodeGen.swift | 14 +- .../_StringProcessing/MatchingOptions.swift | 2 +- Sources/_StringProcessing/Regex/DSLTree.swift | 25 +- ...Class.swift => _CharacterClassModel.swift} | 64 +++--- Tests/RegexBuilderTests/RegexDSLTests.swift | 53 +++++ 6 files changed, 338 insertions(+), 35 deletions(-) create mode 100644 Sources/RegexBuilder/CharacterClass.swift rename Sources/_StringProcessing/{CharacterClass.swift => _CharacterClassModel.swift} (90%) diff --git a/Sources/RegexBuilder/CharacterClass.swift b/Sources/RegexBuilder/CharacterClass.swift new file mode 100644 index 000000000..78ebd49a2 --- /dev/null +++ b/Sources/RegexBuilder/CharacterClass.swift @@ -0,0 +1,215 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +import _RegexParser +@_spi(RegexBuilder) import _StringProcessing + +public struct CharacterClass { + internal var ccc: DSLTree.CustomCharacterClass + + init(_ ccc: DSLTree.CustomCharacterClass) { + self.ccc = ccc + } + + init(unconverted model: _CharacterClassModel) { + // FIXME: Implement in DSLTree instead of wrapping an AST atom + switch model.makeAST() { + case .atom(let atom): + self.ccc = .init(members: [.atom(.unconverted(atom))]) + default: + fatalError("Unsupported _CharacterClassModel") + } + } + + init(property: AST.Atom.CharacterProperty) { + // FIXME: Implement in DSLTree instead of wrapping an AST atom + let astAtom = AST.Atom(.property(property), .fake) + self.ccc = .init(members: [.atom(.unconverted(astAtom))]) + } +} + +extension CharacterClass: RegexComponent { + public var regex: Regex { + return Regex(node: DSLTree.Node.customCharacterClass(ccc)) + } +} + +extension CharacterClass { + public var inverted: CharacterClass { + CharacterClass(ccc.inverted) + } +} + +extension RegexComponent where Self == CharacterClass { + public static var any: CharacterClass { + .init(DSLTree.CustomCharacterClass(members: [.atom(.any)])) + } + + public static var anyGrapheme: CharacterClass { + .init(unconverted: .anyGrapheme) + } + + public static var whitespace: CharacterClass { + .init(unconverted: .whitespace) + } + + public static var digit: CharacterClass { + .init(unconverted: .digit) + } + + public static var hexDigit: CharacterClass { + .init(DSLTree.CustomCharacterClass(members: [ + .range(.char("A"), .char("F")), + .range(.char("a"), .char("f")), + .range(.char("0"), .char("9")), + ])) + } + + public static var horizontalWhitespace: CharacterClass { + .init(unconverted: .horizontalWhitespace) + } + + public static var newlineSequence: CharacterClass { + .init(unconverted: .newlineSequence) + } + + public static var verticalWhitespace: CharacterClass { + .init(unconverted: .verticalWhitespace) + } + + public static var word: CharacterClass { + .init(unconverted: .word) + } +} + +extension RegexComponent where Self == CharacterClass { + /// Returns a character class that matches any character in the given string + /// or sequence. + public static func anyOf(_ s: S) -> CharacterClass + where S.Element == Character + { + CharacterClass(DSLTree.CustomCharacterClass( + members: s.map { .atom(.char($0)) })) + } + + /// Returns a character class that matches any unicode scalar in the given + /// sequence. + public static func anyOf(_ s: S) -> CharacterClass + where S.Element == UnicodeScalar + { + CharacterClass(DSLTree.CustomCharacterClass( + members: s.map { .atom(.scalar($0)) })) + } +} + +// Unicode properties +extension CharacterClass { + public static func generalCategory(_ category: Unicode.GeneralCategory) -> CharacterClass { + guard let extendedCategory = category.extendedGeneralCategory else { + fatalError("Unexpected general category") + } + return CharacterClass(property: + .init(.generalCategory(extendedCategory), isInverted: false, isPOSIX: false)) + } +} + +/// Range syntax for characters in `CharacterClass`es. +public func ...(lhs: Character, rhs: Character) -> CharacterClass { + let range: DSLTree.CustomCharacterClass.Member = .range(.char(lhs), .char(rhs)) + let ccc = DSLTree.CustomCharacterClass(members: [range], isInverted: false) + return CharacterClass(ccc) +} + +/// Range syntax for unicode scalars in `CharacterClass`es. +@_disfavoredOverload +public func ...(lhs: UnicodeScalar, rhs: UnicodeScalar) -> CharacterClass { + let range: DSLTree.CustomCharacterClass.Member = .range(.scalar(lhs), .scalar(rhs)) + let ccc = DSLTree.CustomCharacterClass(members: [range], isInverted: false) + return CharacterClass(ccc) +} + +extension Unicode.GeneralCategory { + var extendedGeneralCategory: Unicode.ExtendedGeneralCategory? { + switch self { + case .uppercaseLetter: return .uppercaseLetter + case .lowercaseLetter: return .lowercaseLetter + case .titlecaseLetter: return .titlecaseLetter + case .modifierLetter: return .modifierLetter + case .otherLetter: return .otherLetter + case .nonspacingMark: return .nonspacingMark + case .spacingMark: return .spacingMark + case .enclosingMark: return .enclosingMark + case .decimalNumber: return .decimalNumber + case .letterNumber: return .letterNumber + case .otherNumber: return .otherNumber + case .connectorPunctuation: return .connectorPunctuation + case .dashPunctuation: return .dashPunctuation + case .openPunctuation: return .openPunctuation + case .closePunctuation: return .closePunctuation + case .initialPunctuation: return .initialPunctuation + case .finalPunctuation: return .finalPunctuation + case .otherPunctuation: return .otherPunctuation + case .mathSymbol: return .mathSymbol + case .currencySymbol: return .currencySymbol + case .modifierSymbol: return .modifierSymbol + case .otherSymbol: return .otherSymbol + case .spaceSeparator: return .spaceSeparator + case .lineSeparator: return .lineSeparator + case .paragraphSeparator: return .paragraphSeparator + case .control: return .control + case .format: return .format + case .surrogate: return .surrogate + case .privateUse: return .privateUse + case .unassigned: return .unassigned + @unknown default: return nil + } + } +} + +// MARK: - Set algebra methods + +extension RegexComponent where Self == CharacterClass { + public init(_ first: CharacterClass, _ rest: CharacterClass...) { + if rest.isEmpty { + self.init(first.ccc) + } else { + let members: [DSLTree.CustomCharacterClass.Member] = + (CollectionOfOne(first) + rest).map { .custom($0.ccc) } + self.init(.init(members: members)) + } + } +} + +extension CharacterClass { + public func union(_ other: CharacterClass) -> CharacterClass { + CharacterClass(.init(members: [ + .custom(self.ccc), + .custom(other.ccc)])) + } + + public func intersection(_ other: CharacterClass) -> CharacterClass { + CharacterClass(.init(members: [ + .intersection(self.ccc, other.ccc) + ])) + } + + public func subtracting(_ other: CharacterClass) -> CharacterClass { + CharacterClass(.init(members: [ + .subtraction(self.ccc, other.ccc) + ])) + } + + public func symmetricDifference(_ other: CharacterClass) -> CharacterClass { + CharacterClass(.init(members: [ + .symmetricDifference(self.ccc, other.ccc) + ])) + } +} diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index d6d6c3c5e..ed84fadbd 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -136,7 +136,7 @@ extension Compiler.ByteCodeGen { // TODO: May want to consider Unicode level builder.buildAssert { [options] (input, pos, bounds) in // TODO: How should we handle bounds? - CharacterClass.word.isBoundary( + _CharacterClassModel.word.isBoundary( input, at: pos, bounds: bounds, with: options) } @@ -144,7 +144,7 @@ extension Compiler.ByteCodeGen { // TODO: May want to consider Unicode level builder.buildAssert { [options] (input, pos, bounds) in // TODO: How should we handle bounds? - !CharacterClass.word.isBoundary( + !_CharacterClassModel.word.isBoundary( input, at: pos, bounds: bounds, with: options) } } @@ -595,7 +595,15 @@ extension Compiler.ByteCodeGen { try emitQuantification(amt, kind, child) case let .customCharacterClass(ccc): - try emitCustomCharacterClass(ccc) + if ccc.containsAny { + if !ccc.isInverted { + emitAny() + } else { + throw Unsupported("Inverted any") + } + } else { + try emitCustomCharacterClass(ccc) + } case let .atom(a): try emitAtom(a) diff --git a/Sources/_StringProcessing/MatchingOptions.swift b/Sources/_StringProcessing/MatchingOptions.swift index c4b2b8de7..cafb07da0 100644 --- a/Sources/_StringProcessing/MatchingOptions.swift +++ b/Sources/_StringProcessing/MatchingOptions.swift @@ -105,7 +105,7 @@ extension MatchingOptions { // Deprecated CharacterClass.MatchLevel API extension MatchingOptions { @available(*, deprecated) - var matchLevel: CharacterClass.MatchLevel { + var matchLevel: _CharacterClassModel.MatchLevel { switch semanticLevel { case .graphemeCluster: return .graphemeCluster diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index bd3b37a3d..59ebd38af 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -107,8 +107,31 @@ extension DSLTree { public struct CustomCharacterClass { var members: [Member] var isInverted: Bool + + var containsAny: Bool { + members.contains { member in + switch member { + case .atom(.any): return true + case .custom(let ccc): return ccc.containsAny + default: + return false + } + } + } + + public init(members: [DSLTree.CustomCharacterClass.Member], isInverted: Bool = false) { + self.members = members + self.isInverted = isInverted + } + + public var inverted: CustomCharacterClass { + var result = self + result.isInverted.toggle() + return result + } - enum Member { + @_spi(RegexBuilder) + public enum Member { case atom(Atom) case range(Atom, Atom) case custom(CustomCharacterClass) diff --git a/Sources/_StringProcessing/CharacterClass.swift b/Sources/_StringProcessing/_CharacterClassModel.swift similarity index 90% rename from Sources/_StringProcessing/CharacterClass.swift rename to Sources/_StringProcessing/_CharacterClassModel.swift index bdf34d0a7..94a42b549 100644 --- a/Sources/_StringProcessing/CharacterClass.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -15,7 +15,8 @@ import _RegexParser // an AST, but this isn't a natural thing to produce in the context // of parsing or to store in an AST -public struct CharacterClass: Hashable { +@_spi(RegexBuilder) +public struct _CharacterClassModel: Hashable { /// The actual character class to match. var cc: Representation @@ -54,6 +55,7 @@ public struct CharacterClass: Hashable { public typealias SetOperator = AST.CustomCharacterClass.SetOp /// A binary set operation that forms a character class component. + @_spi(RegexBuilder) public struct SetOperation: Hashable { var lhs: CharacterSetComponent var op: SetOperator @@ -71,12 +73,13 @@ public struct CharacterClass: Hashable { } } + @_spi(RegexBuilder) public enum CharacterSetComponent: Hashable { case character(Character) case range(ClosedRange) /// A nested character class. - case characterClass(CharacterClass) + case characterClass(_CharacterClassModel) /// A binary set operation of character class components. indirect case setOperation(SetOperation) @@ -201,7 +204,7 @@ public struct CharacterClass: Hashable { } } -extension CharacterClass: RegexComponent { +extension _CharacterClassModel: RegexComponent { public typealias Output = Substring public var regex: Regex { @@ -212,51 +215,52 @@ extension CharacterClass: RegexComponent { } } -extension RegexComponent where Self == CharacterClass { - public static var any: CharacterClass { +@_spi(RegexBuilder) +extension _CharacterClassModel { + public static var any: _CharacterClassModel { .init(cc: .any, matchLevel: .graphemeCluster) } - public static var anyGrapheme: CharacterClass { + public static var anyGrapheme: _CharacterClassModel { .init(cc: .anyGrapheme, matchLevel: .graphemeCluster) } - public static var whitespace: CharacterClass { + public static var whitespace: _CharacterClassModel { .init(cc: .whitespace, matchLevel: .graphemeCluster) } - public static var digit: CharacterClass { + public static var digit: _CharacterClassModel { .init(cc: .digit, matchLevel: .graphemeCluster) } - public static var hexDigit: CharacterClass { + public static var hexDigit: _CharacterClassModel { .init(cc: .hexDigit, matchLevel: .graphemeCluster) } - public static var horizontalWhitespace: CharacterClass { + public static var horizontalWhitespace: _CharacterClassModel { .init(cc: .horizontalWhitespace, matchLevel: .graphemeCluster) } - public static var newlineSequence: CharacterClass { + public static var newlineSequence: _CharacterClassModel { .init(cc: .newlineSequence, matchLevel: .graphemeCluster) } - public static var verticalWhitespace: CharacterClass { + public static var verticalWhitespace: _CharacterClassModel { .init(cc: .verticalWhitespace, matchLevel: .graphemeCluster) } - public static var word: CharacterClass { + public static var word: _CharacterClassModel { .init(cc: .word, matchLevel: .graphemeCluster) } public static func custom( - _ components: [CharacterClass.CharacterSetComponent] - ) -> CharacterClass { + _ components: [_CharacterClassModel.CharacterSetComponent] + ) -> _CharacterClassModel { .init(cc: .custom(components), matchLevel: .graphemeCluster) } } -extension CharacterClass.CharacterSetComponent: CustomStringConvertible { +extension _CharacterClassModel.CharacterSetComponent: CustomStringConvertible { public var description: String { switch self { case .range(let range): return "" @@ -267,7 +271,7 @@ extension CharacterClass.CharacterSetComponent: CustomStringConvertible { } } -extension CharacterClass.Representation: CustomStringConvertible { +extension _CharacterClassModel.Representation: CustomStringConvertible { public var description: String { switch self { case .any: return "" @@ -284,13 +288,13 @@ extension CharacterClass.Representation: CustomStringConvertible { } } -extension CharacterClass: CustomStringConvertible { +extension _CharacterClassModel: CustomStringConvertible { public var description: String { return "\(isInverted ? "not " : "")\(cc)" } } -extension CharacterClass { +extension _CharacterClassModel { public func makeAST() -> AST.Node? { let inv = isInverted @@ -343,7 +347,7 @@ extension CharacterClass { } extension DSLTree.Node { - var characterClass: CharacterClass? { + var characterClass: _CharacterClassModel? { switch self { case let .customCharacterClass(ccc): return ccc.modelCharacterClass @@ -358,10 +362,10 @@ extension DSLTree.Node { } } -extension CharacterClass { +extension _CharacterClassModel { public func withMatchLevel( - _ level: CharacterClass.MatchLevel - ) -> CharacterClass { + _ level: _CharacterClassModel.MatchLevel + ) -> _CharacterClassModel { var cc = self cc.matchLevel = level return cc @@ -369,7 +373,7 @@ extension CharacterClass { } extension DSLTree.Atom { - var characterClass: CharacterClass? { + var characterClass: _CharacterClassModel? { switch self { case let .unconverted(a): return a.characterClass @@ -380,7 +384,7 @@ extension DSLTree.Atom { } extension AST.Atom { - var characterClass: CharacterClass? { + var characterClass: _CharacterClassModel? { switch kind { case let .escaped(b): return b.characterClass @@ -406,7 +410,7 @@ extension AST.Atom { } extension AST.Atom.EscapedBuiltin { - var characterClass: CharacterClass? { + var characterClass: _CharacterClassModel? { switch self { case .decimalDigit: return .digit case .notDecimalDigit: return .digit.inverted @@ -437,9 +441,9 @@ extension AST.Atom.EscapedBuiltin { extension DSLTree.CustomCharacterClass { // TODO: Refactor a bit, and... can we drop this type? - var modelCharacterClass: CharacterClass? { + var modelCharacterClass: _CharacterClassModel? { var result = - Array() + Array<_CharacterClassModel.CharacterSetComponent>() for m in members { switch m { case let .atom(a): @@ -505,12 +509,12 @@ extension DSLTree.CustomCharacterClass { break } } - let cc = CharacterClass.custom(result) + let cc = _CharacterClassModel.custom(result) return isInverted ? cc.inverted : cc } } -extension CharacterClass { +extension _CharacterClassModel { // FIXME: Calling on inverted sets wont be the same as the // inverse of a boundary if at the start or end of the // string. (Think through what we want: do it ourselves or diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 2044c8859..aaa3f6886 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -70,6 +70,59 @@ class RegexDSLTests: XCTestCase { Capture(.whitespace) // Substring Capture("c") // Substring } + + try _testDSLCaptures( + ("abc1def2", "abc1def2"), + matchType: Substring.self, ==) + { + // First group + OneOrMore { + CharacterClass("a"..."z", .digit) + } + + // Second group + OneOrMore { + ChoiceOf { + "a"..."z" + CharacterClass.hexDigit + } + } + } + + try _testDSLCaptures( + ("abc1def2", ("abc1def2", "abc1")), + matchType: (Substring, Substring).self, ==) + { + Capture { + OneOrMore(.digit.inverted) + ("a"..."z").inverted + } + + OneOrMore { + CharacterClass.whitespace.inverted + } + } + } + + func testCharacterClassOperations() throws { + try _testDSLCaptures( + ("bcdefn1a", "bcdefn1a"), + ("nbcdef1a", nil), // fails symmetric difference lookahead + ("abcdef1a", nil), // fails union + ("bcdef3a", nil), // fails subtraction + ("bcdef1z", nil), // fails intersection + matchType: Substring.self, ==) + { + let disallowedChars = CharacterClass.hexDigit + .symmetricDifference("a"..."z") + Lookahead(disallowedChars, negative: true) // No: 0-9 + g-z + + OneOrMore(("b"..."g").union("d"..."n")) // b-n + + CharacterClass.digit.subtracting("3"..."9") // 1, 2, non-ascii digits + + CharacterClass.hexDigit.intersection("a"..."z") // a-f + } } func testMatchResultDotZeroWithoutCapture() throws { From b41edbd9a2288d160b8e9e1f0aaa709a60ce161d Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Fri, 8 Apr 2022 12:17:11 +0100 Subject: [PATCH 041/133] Author links --- Documentation/Evolution/DelimiterSyntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 39cf87551..ddf1603c4 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -1,6 +1,6 @@ # Regex Literals -- Authors: Hamish Knight, Michael Ilseman, David Ewing +- Authors: [Hamish Knight](https://github.com/hamishknight), [Michael Ilseman](https://github.com/milseman), [David Ewing](https://github.com/DaveEwing) ## Introduction From 0c2ed87b932b7d8b463054e981403b88bd6e109c Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Fri, 8 Apr 2022 08:29:31 -0600 Subject: [PATCH 042/133] Update regex syntax pitch (#258) * Update regex syntax pitch * Rename file --- ...x.md => RegexSyntaxRunTimeConstruction.md} | 97 +++++++++++++++++-- .../Regex/AnyRegexOutput.swift | 29 ++++++ 2 files changed, 118 insertions(+), 8 deletions(-) rename Documentation/Evolution/{RegexSyntax.md => RegexSyntaxRunTimeConstruction.md} (92%) diff --git a/Documentation/Evolution/RegexSyntax.md b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md similarity index 92% rename from Documentation/Evolution/RegexSyntax.md rename to Documentation/Evolution/RegexSyntaxRunTimeConstruction.md index 97e3b45da..d0e04a1f7 100644 --- a/Documentation/Evolution/RegexSyntax.md +++ b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md @@ -2,7 +2,7 @@ Hello, we want to issue an update to [Regular Expression Literals](https://forums.swift.org/t/pitch-regular-expression-literals/52820) and prepare for a formal proposal. The great delimiter deliberation continues to unfold, so in the meantime, we have a significant amount of surface area to present for review/feedback: the syntax _inside_ a regex literal. Additionally, this is the syntax accepted from a string used for run-time regex construction, so we're devoting an entire pitch/proposal to the topic of _regex syntax_, distinct from the result builder DSL or the choice of delimiters for literals. --> -# Run-time Regex Construction +# Regex Syntax and Run-time Construction - Authors: [Hamish Knight](https://github.com/hamishknight), [Michael Ilseman](https://github.com/milseman) @@ -16,7 +16,7 @@ The overall story is laid out in [Regex Type and Overview][overview] and each in Swift aims to be a pragmatic programming language, striking a balance between familiarity, interoperability, and advancing the art. Swift's `String` presents a uniquely Unicode-forward model of string, but currently suffers from limited processing facilities. -`NSRegularExpression` can construct a processing pipeline from a string containing [ICU regular expression syntax][icu-syntax]. However, it is inherently tied to ICU's engine and thus it operates over a fundamentally different model of string than Swift's `String`. It is also limited in features and carries a fair amount of Objective-C baggage. +`NSRegularExpression` can construct a processing pipeline from a string containing [ICU regular expression syntax][icu-syntax]. However, it is inherently tied to ICU's engine and thus it operates over a fundamentally different model of string than Swift's `String`. It is also limited in features and carries a fair amount of Objective-C baggage, such as the need to translate between `NSRange` and `Range`. ```swift let pattern = #"(\w+)\s\s+(\S+)\s\s+((?:(?!\s\s).)*)\s\s+(.*)"# @@ -42,7 +42,7 @@ func processEntry(_ line: String) -> Transaction? { } ``` -Fixing these fundamental limitations requires migrating to a completely different engine and type system representation. This is the path we're proposing with `Regex`, outlined in [Regex Type and Overview][overview]. Details on the semantic mismatch between ICU and Swift's `String` is discussed in [Unicode for String Processing][pitches]. +Fixing these fundamental limitations requires migrating to a completely different engine and type system representation. This is the path we're proposing with `Regex`, outlined in [Regex Type and Overview][overview]. Details on the semantic differences between ICU's string model and Swift's `String` is discussed in [Unicode for String Processing][pitches]. Run-time construction is important for tools and editors. For example, SwiftPM allows the user to provide a regular expression to filter tests via `swift test --filter`. @@ -60,7 +60,6 @@ let regex: Regex<(Substring, Substring, Substring, Substring, Substring)> = try! Regex(compiling: pattern) ``` - ### Syntax We propose accepting a syntactic "superset" of the following existing regular expression engines: @@ -80,11 +79,87 @@ Regex syntax will be part of Swift's source-compatibility story as well as its b ## Detailed Design - +We propose initializers to declare and compile a regex from syntax. Upon failure, these initializers throw compilation errors, such as for syntax or type errors. API for retrieving error information is future work. + +```swift +extension Regex { + /// Parse and compile `pattern`, resulting in a strongly-typed capture list. + public init(compiling pattern: String, as: Output.Type = Output.self) throws +} +extension Regex where Output == AnyRegexOutput { + /// Parse and compile `pattern`, resulting in an existentially-typed capture list. + public init(compiling pattern: String) throws +} +``` + +We propose `AnyRegexOutput` for capture types not known at compilation time, alongside casting API to convert to a strongly-typed capture list. + +```swift +/// A type-erased regex output +public struct AnyRegexOutput { + /// Creates a type-erased regex output from an existing output. + /// + /// Use this initializer to fit a regex with strongly typed captures into the + /// use site of a dynamic regex, i.e. one that was created from a string. + public init(_ match: Regex.Match) + + /// Returns a typed output by converting the underlying value to the specified + /// type. + /// + /// - Parameter type: The expected output type. + /// - Returns: The output, if the underlying value can be converted to the + /// output type, or nil otherwise. + public func `as`(_ type: Output.Type) -> Output? +} +extension AnyRegexOutput: RandomAccessCollection { + public struct Element { + /// The range over which a value was captured. `nil` for no-capture. + public var range: Range? + + /// The slice of the input over which a value was captured. `nil` for no-capture. + public var substring: Substring? + + /// The captured value. `nil` for no-capture. + public var value: Any? + } + + // Trivial collection conformance requirements -We propose the following syntax for regex. + public var startIndex: Int { get } + + public var endIndex: Int { get } + + public var count: Int { get } + + public func index(after i: Int) -> Int + + public func index(before i: Int) -> Int + + public subscript(position: Int) -> Element +} +``` + +We propose adding an API to `Regex.Match` to cast the output type to a concrete one. A regex match will lazily create a `Substring` on demand, so casting the match itself saves ARC traffic vs extracting and casting the output. + +```swift +extension Regex.Match where Output == AnyRegexOutput { + /// Creates a type-erased regex match from an existing match. + /// + /// Use this initializer to fit a regex match with strongly typed captures into the + /// use site of a dynamic regex match, i.e. one that was created from a string. + public init(_ match: Regex.Match) + + /// Returns a typed match by converting the underlying values to the specified + /// types. + /// + /// - Parameter type: The expected output type. + /// - Returns: A match generic over the output type if the underlying values can be converted to the + /// output type. Returns `nil` otherwise. + public func `as`(_ type: Output.Type) -> Regex.Match? +} +``` + +The rest of this proposal will be a detailed and exhaustive definition of our proposed regex syntax.
Grammar Notation @@ -856,6 +931,12 @@ We are deferring runtime support for callouts from regex literals as future work ## Alternatives Considered +### Failalbe inits + +There are many ways for compilation to fail, from syntactic errors to unsupported features to type mismatches. In the general case, run-time compilation errors are not recoverable by a tool without modifying the user's input. Even then, the thrown errors contain valuable information as to why compilation failed. For example, swiftpm presents any errors directly to the user. + +As proposed, the errors thrown will be the same errors presented to the Swift compiler, tracking fine-grained source locations with specific reasons why compilation failed. Defining a rich error API is future work, as these errors are rapidly evolving and it is too early to lock in the ABI. + ### Skip the syntax diff --git a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift index cac0e46c3..bd0fc47c9 100644 --- a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift +++ b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift @@ -37,6 +37,7 @@ extension Regex.Match where Output == AnyRegexOutput { } } +/// A type-erased regex output public struct AnyRegexOutput { let input: String fileprivate let _elements: [ElementRepresentation] @@ -70,6 +71,7 @@ extension AnyRegexOutput { /// Returns a typed output by converting the underlying value to the specified /// type. + /// /// - Parameter type: The expected output type. /// - Returns: The output, if the underlying value can be converted to the /// output type, or nil otherwise. @@ -119,13 +121,20 @@ extension AnyRegexOutput: RandomAccessCollection { fileprivate let representation: ElementRepresentation let input: String + /// The range over which a value was captured. `nil` for no-capture. public var range: Range? { representation.bounds } + /// The slice of the input over which a value was captured. `nil` for no-capture. public var substring: Substring? { range.map { input[$0] } } + + /// The captured value, `nil` for no-capture + public var value: Any? { + fatalError() + } } public var startIndex: Int { @@ -152,3 +161,23 @@ extension AnyRegexOutput: RandomAccessCollection { .init(representation: _elements[position], input: input) } } + +extension Regex.Match where Output == AnyRegexOutput { + /// Creates a type-erased regex match from an existing match. + /// + /// Use this initializer to fit a regex match with strongly typed captures into the + /// use site of a dynamic regex match, i.e. one that was created from a string. + public init(_ match: Regex.Match) { + fatalError("FIXME: Not implemented") + } + + /// Returns a typed match by converting the underlying values to the specified + /// types. + /// + /// - Parameter type: The expected output type. + /// - Returns: A match generic over the output type if the underlying values can be converted to the + /// output type. Returns `nil` otherwise. + public func `as`(_ type: Output.Type) -> Regex.Match? { + fatalError("FIXME: Not implemented") + } +} From e0cea6c7fc71ac353076282b0ac511177d723e97 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Fri, 8 Apr 2022 08:31:50 -0600 Subject: [PATCH 043/133] Typo (#259) --- Documentation/Evolution/RegexSyntaxRunTimeConstruction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md index d0e04a1f7..cd922a673 100644 --- a/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md +++ b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md @@ -931,7 +931,7 @@ We are deferring runtime support for callouts from regex literals as future work ## Alternatives Considered -### Failalbe inits +### Failable inits There are many ways for compilation to fail, from syntactic errors to unsupported features to type mismatches. In the general case, run-time compilation errors are not recoverable by a tool without modifying the user's input. Even then, the thrown errors contain valuable information as to why compilation failed. For example, swiftpm presents any errors directly to the user. From 2e80ced0d9e83edf50ff6c96a2f78df6f92a337f Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Fri, 8 Apr 2022 08:35:19 -0600 Subject: [PATCH 044/133] Proposal cleanup (#260) --- Documentation/Evolution/RegexSyntaxRunTimeConstruction.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md index cd922a673..cab21288d 100644 --- a/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md +++ b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md @@ -1,6 +1,3 @@ - # Regex Syntax and Run-time Construction From c5db717d06fe4c42046e716f5906e4c3b90b648e Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Fri, 8 Apr 2022 08:49:01 -0600 Subject: [PATCH 045/133] Update ProposalOverview.md --- Documentation/Evolution/ProposalOverview.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/Evolution/ProposalOverview.md b/Documentation/Evolution/ProposalOverview.md index 24ac0301c..4346932b5 100644 --- a/Documentation/Evolution/ProposalOverview.md +++ b/Documentation/Evolution/ProposalOverview.md @@ -3,14 +3,15 @@ ## Regex Type and Overview -- [Pitch](https://forums.swift.org/t/pitch-regex-type-and-overview/56029) -- Proposal: To-be-scheduled +- [Proposal](https://github.com/apple/swift-evolution/blob/main/proposals/0350-regex-type-overview.md), [Thread](https://forums.swift.org/t/se-0350-regex-type-and-overview/56530) +- [Pitch thread](https://forums.swift.org/t/pitch-regex-type-and-overview/56029) Presents basic Regex type and gives an overview of how everything fits into the overall story ## Regex Builder DSL +- [Proposal](https://github.com/apple/swift-evolution/blob/main/proposals/0351-regex-builder.md), [Thread](https://forums.swift.org/t/se-0351-regex-builder-dsl/56531) - [Pitch thread](https://forums.swift.org/t/pitch-regex-builder-dsl/56007) Covers the result builder approach and basic API. @@ -18,13 +19,12 @@ Covers the result builder approach and basic API. ## Run-time Regex Construction -- Pitch thread: [Regex Syntax](https://forums.swift.org/t/pitch-regex-syntax/55711) +- [Pitch](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md) +- (old) Pitch thread: [Regex Syntax](https://forums.swift.org/t/pitch-regex-syntax/55711) + Brief: Syntactic superset of PCRE2, Oniguruma, ICU, UTS\#18, etc. Covers the "interior" syntax, extended syntaxes, run-time construction of a regex from a string, and details of `AnyRegexOutput`. -Note: The above pitch drills into the syntax, the revised pitch including two initializers and existential details is still under development. - ## Regex Literals - [Draft](https://github.com/apple/swift-experimental-string-processing/pull/187) From 8da68d38bf6b23a39bd0b75ec37047e97a8b8d80 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Fri, 8 Apr 2022 17:22:38 +0100 Subject: [PATCH 046/133] Updated extended delimiter section --- Documentation/Evolution/DelimiterSyntax.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index ddf1603c4..82f6d496b 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -88,14 +88,14 @@ This allows the captures to be referenced as `match.identifier` and `match.hex` ### Extended delimiters `#/.../#`, `##/.../##` -A regex literal may be surrounded by an arbitrary number of balanced pound characters. This is a somewhat similar to the raw string literal syntax introduced by [SE-0200], and allows a regex literal to use forward slashes without the need to escape them, e.g: +Backslashes may be used to write forward slashes within the regex literal, e.g `/foo\/bar/`. However, this can be quite syntactically noisy and confusing. To avoid this, a regex literal may be surrounded by an arbitrary number of balanced pound characters. This changes the delimiter of the literal, and therefore allows the use of forward slashes without escaping. For example: ```swift let regex = #/usr/lib/modules/([^/]+)/vmlinuz/# // regex: Regex<(Substring, Substring)> ``` -Additionally, it allows for a multi-line mode when the opening delimiter is followed by a new line. +The number of pounds may be further increased to allow the use of e.g `/#` within the literal. This is similar in style to the raw string literal syntax introduced by [SE-0200], however it has a couple of key differences. The escaping rules for backslashes do not change, and a multi-line mode is entered when the opening delimiter is followed by a newline. #### Escaping of backslashes From 5af9ca518c38c11c385bd6e8912c4aef883c9ef9 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 8 Apr 2022 14:04:59 -0500 Subject: [PATCH 047/133] Eliminate extra public API (#256) These were mostly leftover bits from testing :wave: --- Package.swift | 1 + .../Participants/RegexParticipant.swift | 8 +++---- .../PatternConverter/PatternConverter.swift | 2 +- .../Consumers/PredicateConsumer.swift | 8 +++---- .../Algorithms/Consumers/RegexConsumer.swift | 18 ++++++++-------- .../Algorithms/Searchers/TwoWaySearcher.swift | 8 +++---- .../Algorithms/Searchers/ZSearcher.swift | 6 +++--- .../_StringProcessing/MatchingOptions.swift | 2 +- .../_StringProcessing/PrintAsPattern.swift | 1 + Sources/_StringProcessing/Regex/Core.swift | 21 ------------------- .../Utility/ASTBuilder.swift | 8 +++---- .../_CharacterClassModel.swift | 16 +++++++------- Tests/RegexBuilderTests/RegexDSLTests.swift | 6 +++--- 13 files changed, 43 insertions(+), 62 deletions(-) diff --git a/Package.swift b/Package.swift index e95d98b67..47a73ca72 100644 --- a/Package.swift +++ b/Package.swift @@ -22,6 +22,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"), + .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/Sources/Exercises/Participants/RegexParticipant.swift b/Sources/Exercises/Participants/RegexParticipant.swift index a40de3953..71018d8a7 100644 --- a/Sources/Exercises/Participants/RegexParticipant.swift +++ b/Sources/Exercises/Participants/RegexParticipant.swift @@ -69,10 +69,10 @@ private func graphemeBreakPropertyData( private func graphemeBreakPropertyDataLiteral( forLine line: String ) -> GraphemeBreakEntry? { - return graphemeBreakPropertyData( - forLine: line, - using: r(#"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, - matching: (Substring, Substring, Substring?, Substring).self)) + let regex = try! Regex( + compiling: #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, + as: (Substring, Substring, Substring?, Substring).self) + return graphemeBreakPropertyData(forLine: line, using: regex) } // MARK: - Builder DSL diff --git a/Sources/PatternConverter/PatternConverter.swift b/Sources/PatternConverter/PatternConverter.swift index ff47e4be2..f66204884 100644 --- a/Sources/PatternConverter/PatternConverter.swift +++ b/Sources/PatternConverter/PatternConverter.swift @@ -13,7 +13,7 @@ import ArgumentParser import _RegexParser -import _StringProcessing +@_spi(PatternConverter) import _StringProcessing @main struct PatternConverter: ParsableCommand { diff --git a/Sources/_StringProcessing/Algorithms/Consumers/PredicateConsumer.swift b/Sources/_StringProcessing/Algorithms/Consumers/PredicateConsumer.swift index c9b92b9ec..caf523d1c 100644 --- a/Sources/_StringProcessing/Algorithms/Consumers/PredicateConsumer.swift +++ b/Sources/_StringProcessing/Algorithms/Consumers/PredicateConsumer.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -public struct PredicateConsumer { +struct PredicateConsumer { let predicate: (Consumed.Element) -> Bool } @@ -29,7 +29,7 @@ extension PredicateConsumer: CollectionConsumer { extension PredicateConsumer: BidirectionalCollectionConsumer where Consumed: BidirectionalCollection { - public func consumingBack( + func consumingBack( _ consumed: Consumed, in range: Range ) -> Consumed.Index? { @@ -59,9 +59,9 @@ extension PredicateConsumer: BackwardCollectionSearcher, BackwardStatelessCollectionSearcher where Searched: BidirectionalCollection { - public typealias BackwardSearched = Consumed + typealias BackwardSearched = Consumed - public func searchBack( + func searchBack( _ searched: BackwardSearched, in range: Range ) -> Range? { diff --git a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift index 3ab1e579d..dcc5d9f2b 100644 --- a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift +++ b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift @@ -9,13 +9,13 @@ // //===----------------------------------------------------------------------===// -public struct RegexConsumer< +struct RegexConsumer< R: RegexComponent, Consumed: BidirectionalCollection > where Consumed.SubSequence == Substring { // TODO: Should `Regex` itself implement these protocols? let regex: R - public init(_ regex: R) { + init(_ regex: R) { self.regex = regex } } @@ -36,9 +36,9 @@ extension RegexConsumer { // well, taking advantage of the fact that the captures can be ignored extension RegexConsumer: MatchingCollectionConsumer { - public typealias Match = R.Output + typealias Match = R.Output - public func matchingConsuming( + func matchingConsuming( _ consumed: Consumed, in range: Range ) -> (upperBound: String.Index, match: Match)? { _matchingConsuming(consumed[...], in: range) @@ -47,7 +47,7 @@ extension RegexConsumer: MatchingCollectionConsumer { // TODO: We'll want to bake backwards into the engine extension RegexConsumer: BidirectionalMatchingCollectionConsumer { - public func matchingConsumingBack( + func matchingConsumingBack( _ consumed: Consumed, in range: Range ) -> (lowerBound: String.Index, match: Match)? { var i = range.lowerBound @@ -67,12 +67,12 @@ extension RegexConsumer: BidirectionalMatchingCollectionConsumer { } extension RegexConsumer: MatchingStatelessCollectionSearcher { - public typealias Searched = Consumed + typealias Searched = Consumed // TODO: We'll want to bake search into the engine so it can // take advantage of the structure of the regex itself and // its own internal state - public func matchingSearch( + func matchingSearch( _ searched: Searched, in range: Range ) -> (range: Range, match: Match)? { ConsumerSearcher(consumer: self).matchingSearch(searched, in: range) @@ -81,9 +81,9 @@ extension RegexConsumer: MatchingStatelessCollectionSearcher { // TODO: Bake in search-back to engine too extension RegexConsumer: BackwardMatchingStatelessCollectionSearcher { - public typealias BackwardSearched = Consumed + typealias BackwardSearched = Consumed - public func matchingSearchBack( + func matchingSearchBack( _ searched: BackwardSearched, in range: Range ) -> (range: Range, match: Match)? { ConsumerSearcher(consumer: self).matchingSearchBack(searched, in: range) diff --git a/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift b/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift index 11184f856..5530b4421 100644 --- a/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift +++ b/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -public struct TwoWaySearcher +struct TwoWaySearcher where Searched.Element: Comparable { // TODO: Be generic over the pattern? @@ -36,14 +36,14 @@ public struct TwoWaySearcher } extension TwoWaySearcher: CollectionSearcher { - public struct State { + struct State { let end: Searched.Index var index: Searched.Index var criticalIndex: Searched.Index var memory: (offset: Int, index: Searched.Index)? } - public func state( + func state( for searched: Searched, in range: Range ) -> State { @@ -57,7 +57,7 @@ extension TwoWaySearcher: CollectionSearcher { memory: nil) } - public func search( + func search( _ searched: Searched, _ state: inout State ) -> Range? { diff --git a/Sources/_StringProcessing/Algorithms/Searchers/ZSearcher.swift b/Sources/_StringProcessing/Algorithms/Searchers/ZSearcher.swift index a541dcb7d..e06796e72 100644 --- a/Sources/_StringProcessing/Algorithms/Searchers/ZSearcher.swift +++ b/Sources/_StringProcessing/Algorithms/Searchers/ZSearcher.swift @@ -9,12 +9,12 @@ // //===----------------------------------------------------------------------===// -public struct ZSearcher { +struct ZSearcher { let pattern: [Searched.Element] let z: [Int] let areEquivalent: (Searched.Element, Searched.Element) -> Bool - public init( + init( pattern: [Searched.Element], by areEquivalent: @escaping (Searched.Element, Searched.Element ) -> Bool) { @@ -25,7 +25,7 @@ public struct ZSearcher { } extension ZSearcher: StatelessCollectionSearcher { - public func search( + func search( _ searched: Searched, in range: Range ) -> Range? { diff --git a/Sources/_StringProcessing/MatchingOptions.swift b/Sources/_StringProcessing/MatchingOptions.swift index cafb07da0..0f244f1b8 100644 --- a/Sources/_StringProcessing/MatchingOptions.swift +++ b/Sources/_StringProcessing/MatchingOptions.swift @@ -13,7 +13,7 @@ import _RegexParser /// A type that represents the current state of regex matching options, with /// stack-based scoping. -public struct MatchingOptions { +struct MatchingOptions { fileprivate var stack: [Representation] fileprivate func _invariantCheck() { diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index 0cf16ab05..1998aa75b 100644 --- a/Sources/_StringProcessing/PrintAsPattern.swift +++ b/Sources/_StringProcessing/PrintAsPattern.swift @@ -19,6 +19,7 @@ import _RegexParser extension AST { /// Render as a Pattern DSL + @_spi(PatternConverter) public func renderAsBuilderDSL( maxTopDownLevels: Int? = nil, minBottomUpLevels: Int? = nil diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index 265a7868c..96d0f3a68 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -129,24 +129,3 @@ extension UnicodeScalar: RegexComponent { .init(node: .atom(.scalar(self))) } } - -// MARK: - Testing - -public struct MockRegexLiteral: RegexComponent { - public typealias MatchValue = Substring - public let regex: Regex - - public init( - _ string: String, - _ syntax: SyntaxOptions = .traditional, - matching: Output.Type = Output.self - ) throws { - regex = Regex(ast: try parse(string, syntax)) - } -} - -public func r( - _ s: String, matching matchType: Output.Type = Output.self -) -> MockRegexLiteral { - try! MockRegexLiteral(s, matching: matchType) -} diff --git a/Sources/_StringProcessing/Utility/ASTBuilder.swift b/Sources/_StringProcessing/Utility/ASTBuilder.swift index 8a9af8111..7a8edcd24 100644 --- a/Sources/_StringProcessing/Utility/ASTBuilder.swift +++ b/Sources/_StringProcessing/Utility/ASTBuilder.swift @@ -106,16 +106,16 @@ func negativeLookahead(_ child: AST.Node) -> AST.Node { func negativeLookbehind(_ child: AST.Node) -> AST.Node { group(.negativeLookbehind, child) } -public func nonAtomicLookahead(_ child: AST.Node) -> AST.Node { +func nonAtomicLookahead(_ child: AST.Node) -> AST.Node { group(.nonAtomicLookahead, child) } -public func nonAtomicLookbehind(_ child: AST.Node) -> AST.Node { +func nonAtomicLookbehind(_ child: AST.Node) -> AST.Node { group(.nonAtomicLookbehind, child) } -public func scriptRun(_ child: AST.Node) -> AST.Node { +func scriptRun(_ child: AST.Node) -> AST.Node { group(.scriptRun, child) } -public func atomicScriptRun(_ child: AST.Node) -> AST.Node { +func atomicScriptRun(_ child: AST.Node) -> AST.Node { group(.atomicScriptRun, child) } func changeMatchingOptions( diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index 94a42b549..e184689f1 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -61,7 +61,7 @@ public struct _CharacterClassModel: Hashable { var op: SetOperator var rhs: CharacterSetComponent - public func matches(_ c: Character, with options: MatchingOptions) -> Bool { + func matches(_ c: Character, with options: MatchingOptions) -> Bool { switch op { case .intersection: return lhs.matches(c, with: options) && rhs.matches(c, with: options) @@ -90,7 +90,7 @@ public struct _CharacterClassModel: Hashable { .setOperation(.init(lhs: lhs, op: op, rhs: rhs)) } - public func matches(_ character: Character, with options: MatchingOptions) -> Bool { + func matches(_ character: Character, with options: MatchingOptions) -> Bool { switch self { case .character(let c): if options.isCaseInsensitive { @@ -116,20 +116,20 @@ public struct _CharacterClassModel: Hashable { } } - public enum MatchLevel { + enum MatchLevel { /// Match at the extended grapheme cluster level. case graphemeCluster /// Match at the Unicode scalar level. case unicodeScalar } - public var scalarSemantic: Self { + var scalarSemantic: Self { var result = self result.matchLevel = .unicodeScalar return result } - public var graphemeClusterSemantic: Self { + var graphemeClusterSemantic: Self { var result = self result.matchLevel = .graphemeCluster return result @@ -137,7 +137,7 @@ public struct _CharacterClassModel: Hashable { /// Returns an inverted character class if true is passed, otherwise the /// same character class is returned. - public func withInversion(_ invertion: Bool) -> Self { + func withInversion(_ invertion: Bool) -> Self { var copy = self if invertion { copy.isInverted.toggle() @@ -152,7 +152,7 @@ public struct _CharacterClassModel: Hashable { /// Returns the end of the match of this character class in `str`, if /// it matches. - public func matches(in str: String, at i: String.Index, with options: MatchingOptions) -> String.Index? { + func matches(in str: String, at i: String.Index, with options: MatchingOptions) -> String.Index? { switch matchLevel { case .graphemeCluster: let c = str[i] @@ -363,7 +363,7 @@ extension DSLTree.Node { } extension _CharacterClassModel { - public func withMatchLevel( + func withMatchLevel( _ level: _CharacterClassModel.MatchLevel ) -> _CharacterClassModel { var cc = self diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index aaa3f6886..1f5305c59 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -611,9 +611,9 @@ class RegexDSLTests: XCTestCase { } do { - let regexLiteral = try MockRegexLiteral( - #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, - matching: (Substring, Substring, Substring?, Substring).self) + let regexLiteral = try Regex( + compiling: #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, + as: (Substring, Substring, Substring?, Substring).self) let maybeMatchResult = line.matchWhole(regexLiteral) let matchResult = try XCTUnwrap(maybeMatchResult) let (wholeMatch, lower, upper, propertyString) = matchResult.output From 9d0cf04be2e095abbe5c242c446198ef8ce4158e Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Fri, 8 Apr 2022 19:42:57 -0600 Subject: [PATCH 048/133] Update delimiter proposal More details and word smithing. --- Documentation/Evolution/DelimiterSyntax.md | 49 ++++++++++++---------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 82f6d496b..90943ebb2 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -4,11 +4,7 @@ ## Introduction -This proposal helps complete the story told in *[Regex Type and Overview][regex-type]* and [elsewhere][pitch-status]. We propose the introduction of regex literals to Swift source code. The proposed syntax mirrors literals in other programing languages such as Perl, JavaScript and Ruby. As in those languages, literals are delimited with the `/` character: - -```swift -let re = /[0-9]+/ -``` +This proposal helps complete the story told in *[Regex Type and Overview][regex-type]* and [elsewhere][pitch-status]. We propose the introduction of regex literals to Swift source code, providing compile-time checks and typed-capture inference. ## Motivation @@ -37,23 +33,26 @@ let regex = /(?[[:alpha:]]\w*) = (?[0-9A-F]+)/ // regex: Regex<(Substring, identifier: Substring, hex: Substring)> ``` -Forward slashes are a regex term of art, and are used as the delimiters for regex literals in Perl, JavaScript and Ruby (though Perl and Ruby also provide alternatives). Their ubiquity and familiarity makes them a compelling choice for Swift. +Forward slashes are a regex term of art. They are used as the delimiters for regex literals in, e.g., Perl, JavaScript and Ruby. Perl and Ruby additionally allow for [user-selected delimiters](https://perldoc.perl.org/perlop#Quote-and-Quote-like-Operators) to avoid having to escape any slashes inside a regex. For that purpose, we propose the extended literal `#/.../#`. -A regex literal may also be spelled using an extended syntax `#/.../#`, which allows the placement of an arbitrary number of balanced `#` characters around the literal. This syntax may be used to avoid needing to escape forward slashes within the regex. Additionally, it allows for a multi-line mode when the opening delimiter is followed by a new line. +An extended literal, `#/.../#`, avoids the need to escape forward slashes within the regex. It allows an arbitrary number of balanced `#` characters around the literal and escape. When the opening delimiter is followed by a new line, it supports a multi-line literal where whitespace is non-semantic and line-ending comments are ignored. -Within a regex literal, the compiler will parse the regex syntax outlined in *[Regex Construction][internal-syntax]*, and diagnose any errors at compile time. The capture types and labels are automatically inferred based on the capture groups present in the regex. Using a literal allows editors to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see *[Regex builder DSL][regex-dsl]*). +The compiler will parse the contents of a regex literal using regex syntax outlined in *[Regex Construction][internal-syntax]*, diagnosing any errors at compile time. The capture types and labels are automatically inferred based on the capture groups present in the regex. Regex literals allows editors and source tools to support features such as syntax coloring inside the literal, highlighting sub-structure of the regex, and conversion of the literal to an equivalent result builder DSL (see *[Regex builder DSL][regex-dsl]*). A regex literal also allows for seamless composition with the Regex DSL, enabling lightweight intermixing of a regex syntax with other elements of the builder: ```swift -// A regex literal for parsing an amount of currency in dollars or pounds. +// A regex for extracting a currency (dollars or pounds) and amount from input +// with precisely the form /[$£]\d+\.\d{2}/ let regex = Regex { - /([$£])/ + Capture { /[$£]/ } TryCapture { - OneOrMore(.digit) + /\d+/ "." - Repeat(.digit, count: 2) - } transform: { Amount(twoDecimalPlaces: $0) } + /\d{2}/ + } transform: { + Amount(twoDecimalPlaces: $0) + } } ``` @@ -65,7 +64,7 @@ Due to the existing use of `/` in comment syntax and operators, there are some s ### Upgrade path -Due to the source breaking changes needed for the `/.../` syntax, it will be introduced in Swift 6 mode. However, projects will be able to adopt it earlier by using the compiler flag `-enable-regex-literals`. Note this does not affect the extended syntax `#/.../#`, which will be usable immediately. +Due to the source breaking changes needed for the `/.../` syntax, it will be introduced in Swift 6 mode. However, projects will be able to adopt it earlier by using the compiler flag `-enable-regex-literals`. Note this does not affect the extended literal `#/.../#`, which will be usable immediately. ### Named typed captures @@ -84,18 +83,27 @@ func matchHexAssignment(_ input: String) -> (String, Int)? { } ``` -This allows the captures to be referenced as `match.identifier` and `match.hex` instead of `match.1` and `match.2`, which would be the behavior for unnamed capture groups. This label inference behavior is not available in the DSL, however users are able to [bind captures to named variables instead][dsl-captures]. +This allows the captures to be referenced as `match.identifier` and `match.hex`, in addition to numerically (like unnamed capture groups) as `match.1` and `match.2`. This label inference behavior is not available in the DSL, however users are able to [bind captures to named variables instead][dsl-captures]. ### Extended delimiters `#/.../#`, `##/.../##` -Backslashes may be used to write forward slashes within the regex literal, e.g `/foo\/bar/`. However, this can be quite syntactically noisy and confusing. To avoid this, a regex literal may be surrounded by an arbitrary number of balanced pound characters. This changes the delimiter of the literal, and therefore allows the use of forward slashes without escaping. For example: +Backslashes may be used to write forward slashes within the regex literal, e.g `/foo\/bar/`. However, this can be quite syntactically noisy and confusing. To avoid this, a regex literal may be surrounded by an arbitrary number of balanced octothorpes. This changes the delimiter of the literal, and therefore allows the use of forward slashes without escaping. For example: ```swift let regex = #/usr/lib/modules/([^/]+)/vmlinuz/# // regex: Regex<(Substring, Substring)> ``` -The number of pounds may be further increased to allow the use of e.g `/#` within the literal. This is similar in style to the raw string literal syntax introduced by [SE-0200], however it has a couple of key differences. The escaping rules for backslashes do not change, and a multi-line mode is entered when the opening delimiter is followed by a newline. +The number of pounds may be further increased to allow the use of e.g `/#` within the literal. This is similar in style to the raw string literal syntax introduced by [SE-0200], however it has a couple of key differences. The escaping rules for backslashes do not change. Additionally, a multi-line mode, where whitespace and line-ending comments are ignored, is entered when the opening delimiter is followed by a newline. + +```swift +let regex = #/ + /usr/lib/modules/ # Prefix + (? [^/]+) + /vmlinuz # The kernel +#/ +// regex: Regex<(Substring, subpath: Substring)> +``` #### Escaping of backslashes @@ -158,11 +166,11 @@ Perhaps the most obvious parsing ambiguity with `/.../` delimiters is with comme ### Ambiguity with infix operators -There would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required for regex literal interpretation, e.g `x + /y/`. Alternatively, extended syntax may be used, e.g `x+#/y/#`. +There would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required for regex literal interpretation, e.g `x + /y/`. Alternatively, extended literals may be used, e.g `x+#/y/#`. ### Regex syntax limitations -In order to help avoid further parsing ambiguities, a `/.../` regex literal will not be parsed if it starts with a space, tab, or `)` character. Though the latter is already invalid regex syntax. This restriction may be avoided by using extended `#/.../#` syntax. +In order to help avoid further parsing ambiguities, a `/.../` regex literal will not be parsed if it starts with a space, tab, or `)` character. Though the latter is already invalid regex syntax. This restriction may be avoided by using the extended `#/.../#` literal. #### Rationale @@ -194,7 +202,7 @@ let regex = Regex { } ``` -or extended syntax must be used, e.g: +or extended literal must be used, e.g: ```swift let regex = Regex { @@ -378,4 +386,3 @@ We therefore feel this would be a much less compelling feature without first cla [regex-dsl]: https://github.com/apple/swift-evolution/blob/main/proposals/0351-regex-builder.md [dsl-captures]: https://github.com/apple/swift-evolution/blob/main/proposals/0351-regex-builder.md#capture-and-reference - From fed4c53f132a0dcbfcbfa34d9f02c912777a3d85 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Sun, 10 Apr 2022 11:07:22 -0600 Subject: [PATCH 049/133] Throwing customization hooks (#261) * Throwing customization hooks * Adds test to try out throwing custom code. * Adds processor support. * Add throws to capture transform API, plumbing * Remove non-failable try-capture overloads --- Sources/RegexBuilder/Variadics.swift | 822 +++--------------- .../VariadicsGenerator.swift | 78 +- Sources/_RegexParser/Regex/AST/AST.swift | 75 -- Sources/_StringProcessing/ByteCodeGen.swift | 2 +- .../_StringProcessing/Engine/Consume.swift | 1 + .../_StringProcessing/Engine/MEProgram.swift | 6 +- .../_StringProcessing/Engine/Processor.swift | 53 +- Sources/_StringProcessing/Executor.swift | 3 + Sources/_StringProcessing/Regex/DSLTree.swift | 63 +- Sources/_StringProcessing/Regex/Match.swift | 2 +- Tests/RegexBuilderTests/CustomTests.swift | 85 ++ 11 files changed, 339 insertions(+), 851 deletions(-) diff --git a/Sources/RegexBuilder/Variadics.swift b/Sources/RegexBuilder/Variadics.swift index 989e5d463..2f4a6240a 100644 --- a/Sources/RegexBuilder/Variadics.swift +++ b/Sources/RegexBuilder/Variadics.swift @@ -2255,35 +2255,6 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } - @_disfavoredOverload - public init( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture), R.Output == W { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - - @_disfavoredOverload - public init( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture), R.Output == W { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } -} - -extension TryCapture { @_disfavoredOverload public init( _ component: R, @@ -2310,15 +2281,17 @@ extension TryCapture { }, component.regex.root))) } +} +extension TryCapture { @_disfavoredOverload public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture), R.Output == W { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -2327,13 +2300,13 @@ extension TryCapture { public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture), R.Output == W { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -2359,35 +2332,6 @@ extension Capture { component().regex.root)) } - @_disfavoredOverload - public init( - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture), R.Output == W { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - - @_disfavoredOverload - public init( - as reference: Reference, - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture), R.Output == W { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } -} - -extension TryCapture { @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> R, @@ -2414,15 +2358,17 @@ extension TryCapture { }, component().regex.root))) } +} +extension TryCapture { @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture), R.Output == W { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -2431,13 +2377,13 @@ extension TryCapture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture), R.Output == W { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -2458,33 +2404,6 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } - public init( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - - public init( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } -} - -extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -2509,14 +2428,16 @@ extension TryCapture { }, component.regex.root))) } +} +extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -2524,13 +2445,13 @@ extension TryCapture { public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -2554,33 +2475,6 @@ extension Capture { component().regex.root)) } - public init( - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - - public init( - as reference: Reference, - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } -} - -extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -2605,14 +2499,16 @@ extension TryCapture { }, component().regex.root))) } +} +extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -2620,13 +2516,13 @@ extension TryCapture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -2647,33 +2543,6 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } - public init( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - - public init( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } -} - -extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -2698,14 +2567,16 @@ extension TryCapture { }, component.regex.root))) } +} +extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -2713,13 +2584,13 @@ extension TryCapture { public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -2743,33 +2614,6 @@ extension Capture { component().regex.root)) } - public init( - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - - public init( - as reference: Reference, - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } -} - -extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -2794,14 +2638,16 @@ extension TryCapture { }, component().regex.root))) } +} +extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -2809,13 +2655,13 @@ extension TryCapture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -2836,33 +2682,6 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } - public init( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - - public init( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } -} - -extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -2887,14 +2706,16 @@ extension TryCapture { }, component.regex.root))) } +} +extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -2902,13 +2723,13 @@ extension TryCapture { public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -2932,33 +2753,6 @@ extension Capture { component().regex.root)) } - public init( - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - - public init( - as reference: Reference, - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } -} - -extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -2983,14 +2777,16 @@ extension TryCapture { }, component().regex.root))) } +} +extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -2998,13 +2794,13 @@ extension TryCapture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3025,33 +2821,6 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } - public init( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - - public init( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } -} - -extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -3076,14 +2845,16 @@ extension TryCapture { }, component.regex.root))) } +} +extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3091,13 +2862,13 @@ extension TryCapture { public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3121,33 +2892,6 @@ extension Capture { component().regex.root)) } - public init( - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - - public init( - as reference: Reference, - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } -} - -extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -3172,14 +2916,16 @@ extension TryCapture { }, component().regex.root))) } +} +extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3187,13 +2933,13 @@ extension TryCapture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3214,33 +2960,6 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } - public init( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - - public init( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } -} - -extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -3265,14 +2984,16 @@ extension TryCapture { }, component.regex.root))) } +} +extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3280,13 +3001,13 @@ extension TryCapture { public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3306,37 +3027,10 @@ extension Capture { @RegexComponentBuilder _ component: () -> R ) where Output == (Substring, W, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { self.init(node: .capture( - reference: reference.id, - component().regex.root)) - } - - public init( - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - - public init( - as reference: Reference, - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) + reference: reference.id, + component().regex.root)) } -} -extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -3361,14 +3055,16 @@ extension TryCapture { }, component().regex.root))) } +} +extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3376,13 +3072,13 @@ extension TryCapture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3403,33 +3099,6 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } - public init( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - - public init( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } -} - -extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -3454,14 +3123,16 @@ extension TryCapture { }, component.regex.root))) } +} +extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3469,13 +3140,13 @@ extension TryCapture { public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3499,33 +3170,6 @@ extension Capture { component().regex.root)) } - public init( - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - - public init( - as reference: Reference, - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } -} - -extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -3550,14 +3194,16 @@ extension TryCapture { }, component().regex.root))) } +} +extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3565,13 +3211,13 @@ extension TryCapture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3592,33 +3238,6 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } - public init( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - - public init( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } -} - -extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -3643,14 +3262,16 @@ extension TryCapture { }, component.regex.root))) } +} +extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3658,13 +3279,13 @@ extension TryCapture { public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3688,33 +3309,6 @@ extension Capture { component().regex.root)) } - public init( - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - - public init( - as reference: Reference, - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } -} - -extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -3739,14 +3333,16 @@ extension TryCapture { }, component().regex.root))) } +} +extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3754,13 +3350,13 @@ extension TryCapture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3781,33 +3377,6 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } - public init( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - - public init( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } -} - -extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -3832,14 +3401,16 @@ extension TryCapture { }, component.regex.root))) } +} +extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3847,13 +3418,13 @@ extension TryCapture { public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3877,33 +3448,6 @@ extension Capture { component().regex.root)) } - public init( - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - - public init( - as reference: Reference, - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } -} - -extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -3928,14 +3472,16 @@ extension TryCapture { }, component().regex.root))) } +} +extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3943,13 +3489,13 @@ extension TryCapture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3970,33 +3516,6 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } - public init( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - - public init( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } -} - -extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -4021,14 +3540,16 @@ extension TryCapture { }, component.regex.root))) } +} +extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -4036,13 +3557,13 @@ extension TryCapture { public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -4066,33 +3587,6 @@ extension Capture { component().regex.root)) } - public init( - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - - public init( - as reference: Reference, - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } -} - -extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -4117,14 +3611,16 @@ extension TryCapture { }, component().regex.root))) } +} +extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -4132,13 +3628,13 @@ extension TryCapture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -4159,33 +3655,6 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } - public init( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - - public init( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } -} - -extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -4210,14 +3679,16 @@ extension TryCapture { }, component.regex.root))) } +} +extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -4225,13 +3696,13 @@ extension TryCapture { public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -4255,33 +3726,6 @@ extension Capture { component().regex.root)) } - public init( - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - - public init( - as reference: Reference, - @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } -} - -extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -4306,14 +3750,16 @@ extension TryCapture { }, component().regex.root))) } +} +extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -4321,13 +3767,13 @@ extension TryCapture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index dbeff818c..5fbd2bf2d 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -615,35 +615,6 @@ struct VariadicsGenerator: ParsableCommand { self.init(node: .capture(reference: reference.id, component.regex.root)) } - \(disfavored)\ - public init<\(genericParams), NewCapture>( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) \(whereClauseTransformed) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - - \(disfavored)\ - public init<\(genericParams), NewCapture>( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) \(whereClauseTransformed) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component.regex.root))) - } - } - - extension TryCapture { \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, @@ -670,15 +641,17 @@ struct VariadicsGenerator: ParsableCommand { }, component.regex.root))) } + } + extension TryCapture { \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) \(whereClauseTransformed) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -687,13 +660,13 @@ struct VariadicsGenerator: ParsableCommand { public init<\(genericParams), NewCapture>( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) \(whereClauseTransformed) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -719,35 +692,6 @@ struct VariadicsGenerator: ParsableCommand { component().regex.root)) } - \(disfavored)\ - public init<\(genericParams), NewCapture>( - @\(concatBuilderName) _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) \(whereClauseTransformed) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - - \(disfavored)\ - public init<\(genericParams), NewCapture>( - as reference: Reference, - @\(concatBuilderName) _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) \(whereClauseTransformed) { - self.init(node: .capture( - reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - component().regex.root))) - } - } - - extension TryCapture { \(disfavored)\ public init<\(genericParams), NewCapture>( @\(concatBuilderName) _ component: () -> R, @@ -774,15 +718,17 @@ struct VariadicsGenerator: ParsableCommand { }, component().regex.root))) } + } + extension TryCapture { \(disfavored)\ public init<\(genericParams), NewCapture>( @\(concatBuilderName) _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) \(whereClauseTransformed) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -791,13 +737,13 @@ struct VariadicsGenerator: ParsableCommand { public init<\(genericParams), NewCapture>( as reference: Reference, @\(concatBuilderName) _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? + transform: @escaping (Substring) throws -> NewCapture? ) \(whereClauseTransformed) { self.init(node: .capture( reference: reference.id, .transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } diff --git a/Sources/_RegexParser/Regex/AST/AST.swift b/Sources/_RegexParser/Regex/AST/AST.swift index ba37b6d62..409d5a7ee 100644 --- a/Sources/_RegexParser/Regex/AST/AST.swift +++ b/Sources/_RegexParser/Regex/AST/AST.swift @@ -304,78 +304,3 @@ extension AST { } } } - -// FIXME: Get this out of here -public struct CaptureTransform: Equatable, Hashable, CustomStringConvertible { - public enum Closure { - case nonfailable((Substring) -> Any) - case failable((Substring) -> Any?) - case throwing((Substring) throws -> Any) - } - public let resultType: Any.Type - public let closure: Closure - - public init(resultType: Any.Type, closure: Closure) { - self.resultType = resultType - self.closure = closure - } - - public init( - resultType: Any.Type, - _ closure: @escaping (Substring) -> Any - ) { - self.init(resultType: resultType, closure: .nonfailable(closure)) - } - - public init( - resultType: Any.Type, - _ closure: @escaping (Substring) -> Any? - ) { - self.init(resultType: resultType, closure: .failable(closure)) - } - - public init( - resultType: Any.Type, - _ closure: @escaping (Substring) throws -> Any - ) { - self.init(resultType: resultType, closure: .throwing(closure)) - } - - public func callAsFunction(_ input: Substring) -> Any? { - switch closure { - case .nonfailable(let closure): - let result = closure(input) - assert(type(of: result) == resultType) - return result - case .failable(let closure): - guard let result = closure(input) else { - return nil - } - assert(type(of: result) == resultType) - return result - case .throwing(let closure): - do { - let result = try closure(input) - assert(type(of: result) == resultType) - return result - } catch { - return nil - } - } - } - - public static func == (lhs: CaptureTransform, rhs: CaptureTransform) -> Bool { - unsafeBitCast(lhs.closure, to: (Int, Int).self) == - unsafeBitCast(rhs.closure, to: (Int, Int).self) - } - - public func hash(into hasher: inout Hasher) { - let (fn, ctx) = unsafeBitCast(closure, to: (Int, Int).self) - hasher.combine(fn) - hasher.combine(ctx) - } - - public var description: String { - "" - } -} diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index ed84fadbd..70233cf4f 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -317,7 +317,7 @@ extension Compiler.ByteCodeGen { ) throws { let transform = builder.makeTransformFunction { input, range in - t(input[range]) + try t(input[range]) } builder.buildBeginCapture(cap) try emitNode(child) diff --git a/Sources/_StringProcessing/Engine/Consume.swift b/Sources/_StringProcessing/Engine/Consume.swift index 4e00a34b4..bc60ba260 100644 --- a/Sources/_StringProcessing/Engine/Consume.swift +++ b/Sources/_StringProcessing/Engine/Consume.swift @@ -25,6 +25,7 @@ extension Engine { } extension Processor where Input == String { + // TODO: Should we throw here? mutating func consume() -> Input.Index? { while true { switch self.state { diff --git a/Sources/_StringProcessing/Engine/MEProgram.swift b/Sources/_StringProcessing/Engine/MEProgram.swift index a31134cc9..ecd67d4ba 100644 --- a/Sources/_StringProcessing/Engine/MEProgram.swift +++ b/Sources/_StringProcessing/Engine/MEProgram.swift @@ -14,11 +14,11 @@ import _RegexParser struct MEProgram where Input.Element: Equatable { typealias ConsumeFunction = (Input, Range) -> Input.Index? typealias AssertionFunction = - (Input, Input.Index, Range) -> Bool + (Input, Input.Index, Range) throws -> Bool typealias TransformFunction = - (Input, Range) -> Any? + (Input, Range) throws -> Any? typealias MatcherFunction = - (Input, Input.Index, Range) -> (Input.Index, Any)? + (Input, Input.Index, Range) throws -> (Input.Index, Any)? var instructions: InstructionList diff --git a/Sources/_StringProcessing/Engine/Processor.swift b/Sources/_StringProcessing/Engine/Processor.swift index 343b02c92..8f777ad33 100644 --- a/Sources/_StringProcessing/Engine/Processor.swift +++ b/Sources/_StringProcessing/Engine/Processor.swift @@ -51,6 +51,8 @@ struct Processor< var state: State = .inProgress + var failureReason: Error? = nil + var isTracingEnabled: Bool var storedCaptures: Array<_StoredCapture> @@ -181,6 +183,13 @@ extension Processor { registers.ints = intRegisters } + mutating func abort(_ e: Error? = nil) { + if let e = e { + self.failureReason = e + } + self.state = .fail + } + mutating func tryAccept() { switch (currentPosition, matchMode) { // When reaching the end of the match bounds or when we are only doing a @@ -355,8 +364,13 @@ extension Processor { case .assertBy: let reg = payload.assertion let assertion = registers[reg] - guard assertion(input, currentPosition, bounds) else { - signalFailure() + do { + guard try assertion(input, currentPosition, bounds) else { + signalFailure() + return + } + } catch { + abort(error) return } controller.step() @@ -364,15 +378,20 @@ extension Processor { case .matchBy: let (matcherReg, valReg) = payload.pairedMatcherValue let matcher = registers[matcherReg] - guard let (nextIdx, val) = matcher( - input, currentPosition, bounds - ) else { - signalFailure() + do { + guard let (nextIdx, val) = try matcher( + input, currentPosition, bounds + ) else { + signalFailure() + return + } + registers[valReg] = val + advance(to: nextIdx) + controller.step() + } catch { + abort(error) return } - registers[valReg] = val - advance(to: nextIdx) - controller.step() case .print: // TODO: Debug stream @@ -431,14 +450,18 @@ extension Processor { fatalError( "Unreachable: transforming without a capture") } - // FIXME: Pass input or the slice? - guard let value = transform(input, range) else { - signalFailure() + do { + // FIXME: Pass input or the slice? + guard let value = try transform(input, range) else { + signalFailure() + return + } + storedCaptures[capNum].registerValue(value) + controller.step() + } catch { + abort(error) return } - storedCaptures[capNum].registerValue(value) - - controller.step() case .captureValue: let (val, cap) = payload.pairedValueCapture diff --git a/Sources/_StringProcessing/Executor.swift b/Sources/_StringProcessing/Executor.swift index 148ddf468..563e90970 100644 --- a/Sources/_StringProcessing/Executor.swift +++ b/Sources/_StringProcessing/Executor.swift @@ -28,6 +28,9 @@ struct Executor { input: input, bounds: inputRange, matchMode: mode) guard let endIdx = cpu.consume() else { + if let e = cpu.failureReason { + throw e + } return nil } diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index 59ebd38af..f37505cb4 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -164,14 +164,14 @@ extension DSLTree { @_spi(RegexBuilder) public typealias _ConsumerInterface = ( String, Range -) -> String.Index? +) throws -> String.Index? // Type producing consume // TODO: better name @_spi(RegexBuilder) public typealias _MatcherInterface = ( String, String.Index, Range -) -> (String.Index, Any)? +) throws -> (String.Index, Any)? // Character-set (post grapheme segmentation) @_spi(RegexBuilder) @@ -384,3 +384,62 @@ public struct ReferenceID: Hashable, Equatable { Self.counter += 1 } } + +@_spi(RegexBuilder) +public struct CaptureTransform: Hashable, CustomStringConvertible { + public enum Closure { + case failable((Substring) throws -> Any?) + case nonfailable((Substring) throws -> Any) + } + public let resultType: Any.Type + public let closure: Closure + + public init(resultType: Any.Type, closure: Closure) { + self.resultType = resultType + self.closure = closure + } + + public init( + resultType: Any.Type, + _ closure: @escaping (Substring) throws -> Any + ) { + self.init(resultType: resultType, closure: .nonfailable(closure)) + } + + public init( + resultType: Any.Type, + _ closure: @escaping (Substring) throws -> Any? + ) { + self.init(resultType: resultType, closure: .failable(closure)) + } + + public func callAsFunction(_ input: Substring) throws -> Any? { + switch closure { + case .nonfailable(let closure): + let result = try closure(input) + assert(type(of: result) == resultType) + return result + case .failable(let closure): + guard let result = try closure(input) else { + return nil + } + assert(type(of: result) == resultType) + return result + } + } + + public static func == (lhs: CaptureTransform, rhs: CaptureTransform) -> Bool { + unsafeBitCast(lhs.closure, to: (Int, Int).self) == + unsafeBitCast(rhs.closure, to: (Int, Int).self) + } + + public func hash(into hasher: inout Hasher) { + let (fn, ctx) = unsafeBitCast(closure, to: (Int, Int).self) + hasher.combine(fn) + hasher.combine(ctx) + } + + public var description: String { + "" + } +} diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 45d33f03e..5c846c0fd 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -130,7 +130,7 @@ extension RegexComponent { mode: MatchMode = .wholeString ) throws -> Regex.Match? { let executor = Executor(program: regex.program.loweredProgram) - return try executor.match(input, in: inputRange, mode) + return try executor.match(input, in: inputRange, mode) } func _firstMatch( diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index 19c4a3896..79ebc2693 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -138,4 +138,89 @@ class CustomRegexComponentTests: XCTestCase { XCTAssertEqual(res4.output.0, "123") XCTAssertEqual(res4.output.1, 3) } + + func testRegexAbort() { + + enum Radix: Hashable { + case dot + case comma + } + struct Abort: Error, Hashable {} + + let hexRegex = Regex { + Capture { OneOrMore(.hexDigit) } + TryCapture { CharacterClass.any } transform: { c -> Radix? in + switch c { + case ".": return Radix.dot + case ",": return Radix.comma + case "❗️": + // Malicious! Toxic levels of emphasis detected. + throw Abort() + default: + // Not a radix + return nil + } + } + Capture { OneOrMore(.hexDigit) } + } + // hexRegex: Regex<(Substring, Substring, Radix?, Substring)> + // TODO: Why is Radix optional? + + do { + guard let m = try hexRegex.matchWhole("123aef.345") else { + XCTFail() + return + } + XCTAssertEqual(m.0, "123aef.345") + XCTAssertEqual(m.1, "123aef") + XCTAssertEqual(m.2, .dot) + XCTAssertEqual(m.3, "345") + } catch { + XCTFail() + } + + do { + _ = try hexRegex.matchWhole("123aef❗️345") + XCTFail() + } catch let e as Abort { + XCTAssertEqual(e, Abort()) + } catch { + XCTFail() + } + + struct Poison: Error, Hashable {} + + let addressRegex = Regex { + "0x" + Capture(Repeat(.hexDigit, count: 8)) { hex -> Int in + let i = Int(hex, radix: 16)! + if i == 0xdeadbeef { + throw Poison() + } + return i + } + } + + do { + guard let m = try addressRegex.matchWhole("0x1234567f") else { + XCTFail() + return + } + XCTAssertEqual(m.0, "0x1234567f") + XCTAssertEqual(m.1, 0x1234567f) + } catch { + XCTFail() + } + + do { + _ = try addressRegex.matchWhole("0xdeadbeef") + XCTFail() + } catch let e as Poison { + XCTAssertEqual(e, Poison()) + } catch { + XCTFail() + } + + + } } From 720c10c5630989d9a02d2b906656caebf8ed88f2 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 11 Apr 2022 10:43:03 +0100 Subject: [PATCH 050/133] Update Documentation/Evolution/DelimiterSyntax.md Co-authored-by: Michael Ilseman --- Documentation/Evolution/DelimiterSyntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index 90943ebb2..a1514c9a9 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -4,7 +4,7 @@ ## Introduction -This proposal helps complete the story told in *[Regex Type and Overview][regex-type]* and [elsewhere][pitch-status]. We propose the introduction of regex literals to Swift source code, providing compile-time checks and typed-capture inference. +We propose the introduction of regex literals to Swift source code, providing compile-time checks and typed-capture inference. Regex literals help complete the story told in *[Regex Type and Overview][regex-type]*. ## Motivation From c045e21f2d07e552154af96fb0180e19bfafea08 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 11 Apr 2022 10:54:50 +0100 Subject: [PATCH 051/133] Clarify backslash rule --- Documentation/Evolution/DelimiterSyntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index a1514c9a9..f5e8bba87 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -94,7 +94,7 @@ let regex = #/usr/lib/modules/([^/]+)/vmlinuz/# // regex: Regex<(Substring, Substring)> ``` -The number of pounds may be further increased to allow the use of e.g `/#` within the literal. This is similar in style to the raw string literal syntax introduced by [SE-0200], however it has a couple of key differences. The escaping rules for backslashes do not change. Additionally, a multi-line mode, where whitespace and line-ending comments are ignored, is entered when the opening delimiter is followed by a newline. +The number of pounds may be further increased to allow the use of e.g `/#` within the literal. This is similar in style to the raw string literal syntax introduced by [SE-0200], however it has a couple of key differences. Backslashes do not become literal characters. Additionally, a multi-line mode, where whitespace and line-ending comments are ignored, is entered when the opening delimiter is followed by a newline. ```swift let regex = #/ From ff6b4439932faafd98601a4011d71052420df661 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Mon, 11 Apr 2022 10:31:30 -0500 Subject: [PATCH 052/133] Remove docc-plugin dependency (#263) --- Package.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Package.swift b/Package.swift index 47a73ca72..e95d98b67 100644 --- a/Package.swift +++ b/Package.swift @@ -22,7 +22,6 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"), - .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. From 969bd919f6b49f2ae86d92e508b617026b921fdb Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Mon, 11 Apr 2022 09:59:37 -0600 Subject: [PATCH 053/133] Added a Trying it out section --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index e8a6e387e..42586ad2b 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,21 @@ See [Declarative String Processing Overview][decl-string] - [Swift Trunk Development Snapshot](https://www.swift.org/download/#snapshots) DEVELOPMENT-SNAPSHOT-2022-03-09 or later. +## Trying it out + +To try out the functionality provided here, download the latest open source development toolchain. Import `_StringProcessing` in your source file to get access to the API and specify `-Xfrontend -enable-experimental-string-processing` to get access to the literals. + +For example, in a `Package.swift` file's target declaration: + +```swift +.target( + name: "foo", + dependencies: ["depA"], + swiftSettings: [.unsafeFlags(["-Xfrontend", "-enable-experimental-string-processing"])] + ), +``` + + ## Integration with Swift `_RegexParser` and `_StringProcessing` are specially integrated modules that are built as part of apple/swift. From e31262d681a7dc1bda407d67c35d6f2c0e9cecd5 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 11 Apr 2022 18:17:39 +0100 Subject: [PATCH 054/133] Minor tweaks Standardize on "number signs" for mentions of `#` (though a couple of them read better as just the character). Also change the multi-line example to not include a `/` at the start, which matches the single-line version. --- Documentation/Evolution/DelimiterSyntax.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index f5e8bba87..c775aa12e 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -87,18 +87,18 @@ This allows the captures to be referenced as `match.identifier` and `match.hex`, ### Extended delimiters `#/.../#`, `##/.../##` -Backslashes may be used to write forward slashes within the regex literal, e.g `/foo\/bar/`. However, this can be quite syntactically noisy and confusing. To avoid this, a regex literal may be surrounded by an arbitrary number of balanced octothorpes. This changes the delimiter of the literal, and therefore allows the use of forward slashes without escaping. For example: +Backslashes may be used to write forward slashes within the regex literal, e.g `/foo\/bar/`. However, this can be quite syntactically noisy and confusing. To avoid this, a regex literal may be surrounded by an arbitrary number of balanced number signs. This changes the delimiter of the literal, and therefore allows the use of forward slashes without escaping. For example: ```swift let regex = #/usr/lib/modules/([^/]+)/vmlinuz/# // regex: Regex<(Substring, Substring)> ``` -The number of pounds may be further increased to allow the use of e.g `/#` within the literal. This is similar in style to the raw string literal syntax introduced by [SE-0200], however it has a couple of key differences. Backslashes do not become literal characters. Additionally, a multi-line mode, where whitespace and line-ending comments are ignored, is entered when the opening delimiter is followed by a newline. +The number of `#` characters may be further increased to allow the use of e.g `/#` within the literal. This is similar in style to the raw string literal syntax introduced by [SE-0200], however it has a couple of key differences. Backslashes do not become literal characters. Additionally, a multi-line mode, where whitespace and line-ending comments are ignored, is entered when the opening delimiter is followed by a newline. ```swift let regex = #/ - /usr/lib/modules/ # Prefix + usr/lib/modules/ # Prefix (? [^/]+) /vmlinuz # The kernel #/ @@ -143,7 +143,7 @@ let regex = #/ In this mode, [extended regex syntax][extended-regex-syntax] `(?x)` is enabled by default. This means that whitespace becomes non-semantic, and end-of-line comments are supported with `# comment` syntax. -This mode is supported with any (non-zero) number of pound characters in the delimiter. Similar to multi-line strings introduced by [SE-0168], the closing delimiter must appear on a new line. To avoid parsing confusion, such a literal will not be parsed if a closing delimiter is not present. This avoids inadvertently treating the rest of the file as regex if you only type the opening. +This mode is supported with any (non-zero) number of `#` characters in the delimiter. Similar to multi-line strings introduced by [SE-0168], the closing delimiter must appear on a new line. To avoid parsing confusion, such a literal will not be parsed if a closing delimiter is not present. This avoids inadvertently treating the rest of the file as regex if you only type the opening. ### Ambiguities with comment syntax From 0454f1353cd464df1ee11e943deb8833cb42dc77 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 12 Apr 2022 17:43:51 +0100 Subject: [PATCH 055/133] Allow custom character classes to begin with `:` ICU and Oniguruma allow custom character classes to begin with `:`, and only lex a POSIX character property if they detect a closing `:]`. However their behavior for this differs: - ICU will consider *any* `:]` in the regex as a closing delimiter, even e.g `[[:a]][:]`. - Oniguruma will stop if it hits a `]`, so `[[:a]][:]` is treated as a custom character class. However it only scans ahead 20 chars max, and doesn't stop for e.g a nested character class opening `[`. Our detection behavior for this is as follows: - When `[:` is encountered inside a custom character class, scan ahead to the closing `:]`. - While scanning, bail if we see any characters that are obviously invalid property names. Currently this includes `[`, `]`, `}`, as well as a second occurrence of `=`. - Otherwise, if we end on `:]`, consider that a POSIX character property. We could include more metacharacters to bail on, e.g `{`, `(`, `)`, but for now I'm tending on the side of lexing an invalid POSIX character property. We can always relax this in the future (as we'd be turning invalid code into valid code). Users can always escape the initial `:` in `[:` if they want a custom character class. In fact, we may want to suggest this via a warning, as this behavior can be pretty subtle. --- .../Regex/Parse/LexicalAnalysis.swift | 121 +++++++++++++----- Sources/_RegexParser/Regex/Parse/Parse.swift | 4 +- Tests/RegexTests/ParseTests.swift | 39 +++++- 3 files changed, 129 insertions(+), 35 deletions(-) diff --git a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift index c48d53de9..bf53d0ab1 100644 --- a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift +++ b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift @@ -1064,11 +1064,16 @@ extension Source { } mutating func lexCustomCCStart( + context: ParsingContext ) throws -> Located? { recordLoc { src in - // POSIX named sets are atoms. - guard !src.starts(with: "[:") else { return nil } - + // Make sure we don't have a POSIX character property. This may require + // walking to its ending to make sure we have a closing ':]', as otherwise + // we have a custom character class. + // TODO: This behavior seems subtle, could we warn? + guard !src.canLexPOSIXCharacterProperty(context: context) else { + return nil + } if src.tryEat("[") { return src.tryEat("^") ? .inverted : .normal } @@ -1099,12 +1104,38 @@ extension Source { } private mutating func lexPOSIXCharacterProperty( + context: ParsingContext ) throws -> Located? { - try recordLoc { src in - guard src.tryEat(sequence: "[:") else { return nil } - let inverted = src.tryEat("^") - let prop = try src.lexCharacterPropertyContents(end: ":]").value - return .init(prop, isInverted: inverted, isPOSIX: true) + // Only allowed in a custom character class. + guard context.isInCustomCharacterClass else { return nil } + return try recordLoc { src in + try src.tryEating { src in + guard src.tryEat(sequence: "[:") else { return nil } + let inverted = src.tryEat("^") + + // Note we lex the contents and ending *before* classifying, because we + // want to bail with nil if we don't have the right ending. This allows + // the lexing of a custom character class if we don't have a ':]' + // ending. + let (key, value) = src.lexCharacterPropertyKeyValue() + guard src.tryEat(sequence: ":]") else { return nil } + + let prop = try Source.classifyCharacterPropertyContents(key: key, + value: value) + return .init(prop, isInverted: inverted, isPOSIX: true) + } + } + } + + private func canLexPOSIXCharacterProperty(context: ParsingContext) -> Bool { + do { + var src = self + return try src.lexPOSIXCharacterProperty(context: context) != nil + } catch { + // We want to tend on the side of lexing a POSIX character property, so + // even if it is invalid in some way (e.g invalid property names), still + // try and lex it. + return true } } @@ -1129,26 +1160,52 @@ extension Source { } } - private mutating func lexCharacterPropertyContents( - end: String - ) throws -> Located { - try recordLoc { src in - // We should either have: - // - 'x=y' where 'x' is a property key, and 'y' is a value. - // - 'y' where 'y' is a value (or a bool key with an inferred value - // of true), and its key is inferred. - // TODO: We could have better recovery here if we only ate the characters - // that property keys and values can use. - let lhs = src.lexUntil { - $0.isEmpty || $0.peek() == "=" || $0.starts(with: end) - }.value - if src.tryEat("=") { - let rhs = try src.lexUntil(eating: end).value - return try Source.classifyCharacterProperty(key: lhs, value: rhs) + private mutating func lexCharacterPropertyKeyValue( + ) -> (key: String?, value: String) { + func atPossibleEnding(_ src: inout Source) -> Bool { + guard let next = src.peek() else { return true } + switch next { + case "=": + // End of a key. + return true + case ":", "[", "]": + // POSIX character property endings to cover ':]', ']', and '[' as the + // start of a nested character class. + return true + case "}": + // Ending of '\p{'. We cover this for POSIX too as it's not a valid + // character property name anyway, and it's nice not to have diverging + // logic for these cases. + return true + default: + // We may want to handle other metacharacters here, e.g '{', '(', ')', + // as they're not valid character property names. However for now + // let's tend on the side of forming an unknown property name in case + // these characters are ever used in future character property names + // (though it's very unlikely). Users can always escape e.g the ':' + // in '[:' if they definitely want a custom character class. + return false } - try src.expect(sequence: end) - return try Source.classifyCharacterPropertyValueOnly(lhs) } + // We should either have: + // - 'x=y' where 'x' is a property key, and 'y' is a value. + // - 'y' where 'y' is a value (or a bool key with an inferred value of true) + // and its key is inferred. + let lhs = lexUntil(atPossibleEnding).value + if tryEat("=") { + let rhs = lexUntil(atPossibleEnding).value + return (lhs, rhs) + } + return (nil, lhs) + } + + private static func classifyCharacterPropertyContents( + key: String?, value: String + ) throws -> AST.Atom.CharacterProperty.Kind { + if let key = key { + return try classifyCharacterProperty(key: key, value: value) + } + return try classifyCharacterPropertyValueOnly(value) } /// Try to consume a character property. @@ -1164,7 +1221,10 @@ extension Source { let isInverted = src.peek() == "P" src.advance(2) - let prop = try src.lexCharacterPropertyContents(end: "}").value + let (key, value) = src.lexCharacterPropertyKeyValue() + let prop = try Source.classifyCharacterPropertyContents(key: key, + value: value) + try src.expect("}") return .init(prop, isInverted: isInverted, isPOSIX: false) } } @@ -1758,11 +1818,8 @@ extension Source { if !customCC && (src.peek() == ")" || src.peek() == "|") { return nil } // TODO: Store customCC in the atom, if that's useful - // POSIX character property. This is only allowed in a custom character - // class. - // TODO: Can we try and recover and diagnose these outside character - // classes? - if customCC, let prop = try src.lexPOSIXCharacterProperty()?.value { + // POSIX character property. + if let prop = try src.lexPOSIXCharacterProperty(context: context)?.value { return .property(prop) } diff --git a/Sources/_RegexParser/Regex/Parse/Parse.swift b/Sources/_RegexParser/Regex/Parse/Parse.swift index c3aa3500b..d70a1f14f 100644 --- a/Sources/_RegexParser/Regex/Parse/Parse.swift +++ b/Sources/_RegexParser/Regex/Parse/Parse.swift @@ -403,7 +403,7 @@ extension Parser { } // Check if we have the start of a custom character class '['. - if let cccStart = try source.lexCustomCCStart() { + if let cccStart = try source.lexCustomCCStart(context: context) { return .customCharacterClass( try parseCustomCharacterClass(cccStart)) } @@ -487,7 +487,7 @@ extension Parser { while source.peek() != "]" && source.peekCCBinOp() == nil { // Nested custom character class. - if let cccStart = try source.lexCustomCCStart() { + if let cccStart = try source.lexCustomCCStart(context: context) { members.append(.custom(try parseCustomCharacterClass(cccStart))) continue } diff --git a/Tests/RegexTests/ParseTests.swift b/Tests/RegexTests/ParseTests.swift index 5e3defb11..aa0ebbf98 100644 --- a/Tests/RegexTests/ParseTests.swift +++ b/Tests/RegexTests/ParseTests.swift @@ -474,6 +474,26 @@ extension RegexTests { parseTest( "[a^]", charClass("a", "^")) + // These are custom character classes, not invalid POSIX character classes. + // TODO: This behavior is subtle, we ought to warn. + parseTest("[[:space]]", charClass(charClass(":", "s", "p", "a", "c", "e"))) + parseTest("[:space:]", charClass(":", "s", "p", "a", "c", "e", ":")) + parseTest("[:a]", charClass(":", "a")) + parseTest("[a:]", charClass("a", ":")) + parseTest("[:]", charClass(":")) + parseTest("[::]", charClass(":", ":")) + parseTest("[:=:]", charClass(":", "=", ":")) + parseTest("[[:]]", charClass(charClass(":"))) + parseTest("[[:a=b=c:]]", charClass(charClass(":", "a", "=", "b", "=", "c", ":"))) + + parseTest(#"[[:a[b]:]]"#, charClass(charClass(":", "a", charClass("b"), ":"))) + parseTest(#"[[:a]][:]"#, concat(charClass(charClass(":", "a")), charClass(":"))) + parseTest(#"[[:a]]"#, charClass(charClass(":", "a"))) + parseTest(#"[[:}]]"#, charClass(charClass(":", "}"))) + parseTest(#"[[:{]]"#, charClass(charClass(":", "{"))) + parseTest(#"[[:{:]]"#, charClass(posixProp_m(.other(key: nil, value: "{")))) + parseTest(#"[[:}:]]"#, charClass(charClass(":", "}", ":"))) + parseTest( #"\D\S\W"#, concat( @@ -1096,9 +1116,13 @@ extension RegexTests { #"\p{C}+"#, oneOrMore(of: prop(.generalCategory(.other)))) + // TODO: Start erroring on these? parseTest(#"\p{Lx}"#, prop(.other(key: nil, value: "Lx"))) parseTest(#"\p{gcL}"#, prop(.other(key: nil, value: "gcL"))) parseTest(#"\p{x=y}"#, prop(.other(key: "x", value: "y"))) + parseTest(#"\p{aaa(b)}"#, prop(.other(key: nil, value: "aaa(b)"))) + parseTest("[[:a():]]", charClass(posixProp_m(.other(key: nil, value: "a()")))) + parseTest(#"\p{aaa\p{b}}"#, concat(prop(.other(key: nil, value: #"aaa\p{b"#)), "}")) // UAX44-LM3 means all of the below are equivalent. let lowercaseLetter = prop(.generalCategory(.lowercaseLetter)) @@ -2183,7 +2207,11 @@ extension RegexTests { diagnosticTest(#"\N{A"#, .expected("}")) diagnosticTest(#"\N{U+A"#, .expected("}")) diagnosticTest(#"\p{a"#, .expected("}")) - diagnosticTest(#"\p{a="#, .expected("}")) + diagnosticTest(#"\p{a="#, .emptyProperty) + diagnosticTest(#"\p{a=}"#, .emptyProperty) + diagnosticTest(#"\p{a=b"#, .expected("}")) + diagnosticTest(#"\p{aaa[b]}"#, .expected("}")) + diagnosticTest(#"\p{a=b=c}"#, .expected("}")) diagnosticTest(#"(?#"#, .expected(")")) diagnosticTest(#"(?x"#, .expected(")")) @@ -2218,6 +2246,15 @@ extension RegexTests { // the closing bracket. diagnosticTest("[]", .expected("]")) + diagnosticTest("[:a", .expected("]")) + diagnosticTest("[:a:", .expected("]")) + diagnosticTest("[[:a", .expected("]")) + diagnosticTest("[[:a:", .expected("]")) + diagnosticTest("[[:a[:]", .expected("]")) + + diagnosticTest("[[::]]", .emptyProperty) + diagnosticTest("[[:=:]]", .emptyProperty) + // MARK: Bad escapes diagnosticTest("\\", .expectedEscape) From bf7702fbf950a474c5ad7df104472c5afaeb6b5e Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 12 Apr 2022 21:15:10 +0100 Subject: [PATCH 056/133] Update pitch - Add Source Compatibility section - Condense comment syntax ambiguity section - Mention `/.../` being less popular in some communities --- Documentation/Evolution/DelimiterSyntax.md | 29 +++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/DelimiterSyntax.md index c775aa12e..3a9d02a8b 100644 --- a/Documentation/Evolution/DelimiterSyntax.md +++ b/Documentation/Evolution/DelimiterSyntax.md @@ -62,10 +62,6 @@ Due to the existing use of `/` in comment syntax and operators, there are some s ## Detailed design -### Upgrade path - -Due to the source breaking changes needed for the `/.../` syntax, it will be introduced in Swift 6 mode. However, projects will be able to adopt it earlier by using the compiler flag `-enable-regex-literals`. Note this does not affect the extended literal `#/.../#`, which will be usable immediately. - ### Named typed captures Regex literals have their capture types statically determined by the capture groups present. This follows the same inference behavior as [the DSL][regex-dsl], and is explored in more detail in *[Strongly Typed Captures][strongly-typed-captures]*. One aspect of this that is currently unique to the literal is the ability to infer labeled tuple elements for named capture groups. For example: @@ -147,11 +143,9 @@ This mode is supported with any (non-zero) number of `#` characters in the delim ### Ambiguities with comment syntax -Perhaps the most obvious parsing ambiguity with `/.../` delimiters is with comment syntax. - -- An empty regex literal would conflict with line comment syntax `//`. But an empty regex isn't a particularly useful thing to express, and can be disallowed without significant impact. +Line comment syntax `//` and block comment syntax `/*` will continue to be parsed as comments. An empty regex literal is not a particularly useful thing to express, but can be written as `#//#` if desired. `*` would be an invalid starting character of a regex, and therefore does not pose an issue. -- There is a conflict with block comment syntax, when surrounding a regex literal ending with `*`, for example: +A parsing conflict does however arise when a block comment surrounds a regex literal ending with `*`, for example: ```swift /* @@ -159,14 +153,12 @@ Perhaps the most obvious parsing ambiguity with `/.../` delimiters is with comme */ ``` - In this case, the block comment would prematurely end on the second line, rather than extending all the way to the third line as the user would expect. This is already an issue today with `*/` in a string literal, though it is more likely to occur in a regex given the prevalence of the `*` quantifier. This issue can be avoided in many cases by using line comment syntax `//` instead, which it should be noted is the syntax that Xcode uses when commenting out multiple lines. - -- Block comment syntax also means that a regex literal would not be able to start with the `*` character, however this is less of a concern as it would not be valid regex syntax. +In this case, the block comment prematurely ends on the second line, rather than extending all the way to the third line as the user would expect. This is already an issue today with `*/` in a string literal, though it is more likely to occur in a regex given the prevalence of the `*` quantifier. This issue can be avoided in many cases by using line comment syntax `//` instead, which it should be noted is the syntax that Xcode uses when commenting out multiple lines. ### Ambiguity with infix operators -There would be a minor ambiguity with infix operators used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required for regex literal interpretation, e.g `x + /y/`. Alternatively, extended literals may be used, e.g `x+#/y/#`. +There is a minor ambiguity when infix operators are used with regex literals. When used without whitespace, e.g `x+/y/`, the expression will be treated as using an infix operator `+/`. Whitespace is therefore required for regex literal interpretation, e.g `x + /y/`. Alternatively, extended literals may be used, e.g `x+#/y/#`. ### Regex syntax limitations @@ -273,7 +265,7 @@ func baz(_ x: S) -> Int { } ``` -`foo(/, /)` is currently parsed as 2 unapplied operator arguments. `bar(/, 2) + bar(/, 3)` is currently parsed as two independent calls that each take an unapplied `/` operator reference. Both of these would become regex literals arguments, `/, /` and `/, 2) + bar(/` respectively (though the latter would produce a regex error). +`foo(/, /)` is currently parsed as 2 unapplied operator arguments. `bar(/, 2) + bar(/, 3)` is currently parsed as two independent calls that each take an unapplied `/` operator reference. Both of these will become regex literals arguments, `/, /` and `/, 2) + bar(/` respectively (though the latter will produce a regex error). To disambiguate these cases, users will need to surround at least the opening `/` with parentheses, e.g: @@ -290,6 +282,15 @@ This takes advantage of the fact that a regex literal will not be parsed if the
+## Source Compatibility + +As explored above, two source breaking changes are needed for `/.../` syntax: + +- Deprecation of prefix operators containing the `/` character. +- Parsing `/,` and `/]` as the start of a regex literal if a closing `/` is found, rather than an unapplied operator in an argument list. For example, `fn(/, /)` becomes a regex literal rather than two unapplied operator arguments. + +As such, both these changes and the `/.../` syntax will be introduced in Swift 6 mode. However, projects will be able to adopt the syntax earlier by passing the compiler flag `-enable-bare-regex-syntax`. Note this does not affect the extended delimiter syntax `#/.../#`, which will be usable immediately. + ## Future Directions ### Modern literal syntax @@ -300,7 +301,7 @@ However, such a syntax would lose out on the familiarity benefits of standard re ## Alternatives Considered -Given the fact that `/` is an existing term of art for regular expressions, we feel it should be the preferred delimiter syntax. While it has some syntactic ambiguities, we do not feel that they are sufficient to disqualify the syntax. To evaluate this trade-off, below is a list of alternative delimiters that would not have the same ambiguities. +Given the fact that `/.../` is an existing term of art for regular expressions, we feel it should be the preferred delimiter syntax. It should be noted that the syntax has become less popular in some communities such as Perl, however we still feel that it is a compelling choice, especially with extended delimiters `#/.../#`. Additionally, while there has some syntactic ambiguities, we do not feel that they are sufficient to disqualify the syntax. To evaluate this trade-off, below is a list of alternative delimiters that would not have the same ambiguities. ### Prefixed quote `re'...'` From 9c8a1160a044b4d3defff8e3bacff3cd47e5d57b Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 12 Apr 2022 21:15:11 +0100 Subject: [PATCH 057/133] Rename DelimiterSyntax.md -> RegexLiterals.md And remove the old version of the pitch. --- Documentation/Evolution/RegexLiteralPitch.md | 292 ------------------ .../{DelimiterSyntax.md => RegexLiterals.md} | 0 2 files changed, 292 deletions(-) delete mode 100644 Documentation/Evolution/RegexLiteralPitch.md rename Documentation/Evolution/{DelimiterSyntax.md => RegexLiterals.md} (100%) diff --git a/Documentation/Evolution/RegexLiteralPitch.md b/Documentation/Evolution/RegexLiteralPitch.md deleted file mode 100644 index bf2a5dad3..000000000 --- a/Documentation/Evolution/RegexLiteralPitch.md +++ /dev/null @@ -1,292 +0,0 @@ -# Regular Expression Literals - -- Authors: Hamish Knight, Michael Ilseman - -## Introduction - -We propose to introduce a first-class regular expression literal into the language that can take advantage of library support to offer extensible, powerful, and familiar textual pattern matching. - -This is a component of a larger string processing picture. We would like to start a focused discussion surrounding our approach to the literal itself, while acknowledging that evaluating the utility of the literal will ultimately depend on the whole picture (e.g. supporting API). To aid this focused discussion, details such as the representation of captures in the type system, semantic details, extensions to lexing/parsing, additional API, etc., are out of scope of this pitch and thread. Feel free to continue discussion of anything related in the [overview thread][overview]. - -## Motivation - -Regular expressions are a ubiquitous, familiar, and concise syntax for matching and extracting text that satisfies a particular pattern. Syntactically, a regex literal in Swift should: - -- Support a syntax familiar to developers who have learned to use regular expressions in other tools and languages -- Allow reuse of many regular expressions not specifically designed for Swift (e.g. from Stack Overflow or popular programming books) -- Allow libraries to define custom types that can be constructed with regex literals, much like string literals -- Diagnose at compile time if a regex literal uses capabilities that aren't allowed by the type's regex dialect - -Further motivation, examples, and discussion can be found in the [overview thread][overview]. - -## Proposed Solution - -We propose the introduction of a regular expression literal that supports [the PCRE syntax][PCRE], in addition to new standard library protocols `ExpressibleByRegexLiteral` and `RegexLiteralProtocol` that allow for the customization of how the regex literal is interpreted (similar to [string interpolation][stringinterpolation]). The compiler will parse the PCRE syntax within a regex literal, and synthesize calls to corresponding builder methods. Types conforming to `ExpressibleByRegexLiteral` will be able to provide a builder type that opts into supporting various regex constructs through the use of normal function declarations and `@available`. - -_Note: This pitch concerns language syntax and compiler changes alone, it isn't stating what features the stdlib should support in the initial version or in future versions._ - -## Detailed Design - -A regular expression literal will be introduced using `/` delimiters, within which the compiler will parse [PCRE regex syntax][PCRE]: - -```swift -// Matches " = ", extracting the identifier and hex number -let regex = /([[:alpha:]]\w*) = ([0-9A-F]+)/ -``` - -The above regex literal will be inferred to be the default regex literal type `Regex`. Errors in the regex will be diagnosed by the compiler. - -_`Regex` here is a stand-in type, further details about the type such as if or how this will scale to strongly typed captures is still under investigation._ - -_How best to diagnose grapheme-semantic concerns is still under investigation and probably best discussed in their corresponding threads. For example, `Range` is not [countable][countable] and [ordering is not linguistically meaningful][ordering], so validating character class ranges may involve restricting to a semantically-meaningful range (e.g. ASCII). This is best discussed in the (upcoming) character class pitch/thread._ - -The compiler will then transform the literal into a set of builder calls that may be customized by adopting the `ExpressibleByRegexLiteral` protocol. Below is a straw-person transformation of this example: - -```swift -// let regex = /([[:alpha:]]\w*) = ([0-9A-F]+)/ -let regex = { - var builder = T.RegexLiteral() - - // __A4 = /([[:alpha:]]\w*)/ - let __A1 = builder.buildCharacterClass_POSIX_alpha() - let __A2 = builder.buildCharacterClass_w() - let __A3 = builder.buildConcatenate(__A1, __A2) - let __A4 = builder.buildCaptureGroup(__A3) - - // __B1 = / = / - let __B1 = builder.buildLiteral(" = ") - - // __C3 = /([0-9A-F]+)/ - let __C1 = builder.buildCustomCharacterClass(["0"..."9", "A"..."F"]) - let __C2 = builder.buildOneOrMore(__C1) - let __C3 = builder.buildCaptureGroup(__C2) - - let __D1 = builder.buildConcatenate(__A4, __B1, __C3) - return T(regexLiteral: builder.finalize(__D1)) -}() -``` - -In this formulation, the compiler fully parses the regex literal, calling mutating methods on a builder which constructs an AST. Here, the compiler recognizes syntax such as ranges and classifies metacharacters (`buildCharacterClass_w()`). Alternate formulations could involve less reasoning (`buildMetacharacter_w`), or more (`builderCharacterClass_word`). We'd like community feedback on this approach. - -Additionally, it may make sense for the stdlib to provide a `RegexLiteral` conformer that just constructs a string to pass off to a string-based library. Such a type might assume all features are supported unless communicated otherwise, and we'd like community feedback on mechanisms to communicate this (e.g. availability). - -### The `ExpressibleByRegexLiteral` and `RegexLiteralProtocol` protocols - -New `ExpressibleByRegexLiteral` and `RegexLiteralProtocol` protocols will be introduced to the standard library, and will serve a similar purpose to the existing literal protocols `ExpressibleByStringInterpolation` and `StringInterpolationProtocol`. - -```swift -public protocol ExpressibleByRegexLiteral { - associatedtype RegexLiteral : RegexLiteralProtocol = DefaultRegexLiteral - init(regexLiteral: RegexLiteral) -} - -public protocol RegexLiteralProtocol { - init() - - // Informal builder requirements for building a regex literal - // will be specified here. -} -``` - -Types conforming to `ExpressibleByRegexLiteral` will be able to provide a custom type that conforms to `RegexLiteralProtocol`, which will be used to build the resulting regex value. A default conforming type will be provided by the standard library (`DefaultRegexLiteral` here). - -Libraries can extend regex handling logic for their domains. For example, a higher-level library could provide linguistically richer regular expressions by incorporating locale, collation, language dictionaries, and fuzzier matching. Similarly, libraries wrapping different regex engines (e.g. `NSRegularExpression`) can support custom regex literals. - -### Opting into certain regex features - -We intend for the compiler to completely parse [the PCRE syntax][PCRE]. However, types conforming to `RegexLiteralProtocol` might not be able to handle the full feature set. The compiler will look for corresponding function declarations inside `RegexLiteralProtocol` and will emit a compilation error if missing. Conforming types can use `@available` on these function declarations to communicate versioning and add more support in the future. - -This approach of lookup combined with availability allows the stdlib to support more features over time. - -### Impact of using `/` as the delimiter - -#### On comment syntax - -Single line comments use the syntax `//`, which would conflict with the spelling for an empty regex literal. As such, an empty regex literal would be forbidden. - -While not conflicting with the syntax proposed in this pitch, it's also worth noting that the `//` comment syntax (in particular documentation comments that use `///`) would likely preclude the ability to use `///` as a delimiter if we ever wanted to support multi-line regex literals. It's possible though that future multi-line support could be provided through raw regex literals. Alternatively, it could be inferred from the regex options provided. For example, a regex that uses the multi-line option `/(?m)/` could be allowed to span multiple lines. - -Multi-line comments use the `/*` delimiter. As such, a regex literal starting with `*` wouldn't be parsed. This however isn't a major issue as an unqualified `*` is already invalid regex syntax. An escaped `/\*/` regex literal wouldn't be impacted. - -#### On custom infix operators using the `/` character - -Choosing `/` as the delimiter means there will be a conflict for infix operators containing `/` in cases where whitespace isn't used, for example: - -```swift -x+/y/+z -``` - -Should the operators be parsed as `+/` and `/+` respectively, or should this be parsed as `x + /y/ + z`? - -In this case, things can be disambiguated by the user inserting additional whitespace. We therefore could continue to parse `x+/y/+z` as a binary operator chain, and require additional whitespace to interpret `/y/` as a regex literal. - -#### On custom prefix and postfix operators using the `/` character - -There will also be parsing ambiguity with any user-defined prefix and postfix operators containing the `/` character. For example, code such as the following poses an issue: - -```swift -let x = /0; let y = 1/ -``` - -Should this be considered to be two `let` bindings, with each initialization expression using prefix and postfix `/` operators, or is it a single regex literal? - -This also extends more generally to prefix and postfix operators containing the `/` character, e.g: - -```swift -let x = Int { 0 } -} - -let x = 0 -/ 1 / .foo() -``` - -Today, this is parsed as a single binary operator chain `0 / 1 / .foo()`, with `.foo()` becoming an argument to the `/` operator. This is because while Swift does have some parser behavior that is affected by newlines, generally newlines are treated as whitespace, and expressions therefore may span multiple lines. However the user may well be expecting the second line to be parsed as a regex literal. - -This is also potentially an issue for result builders, for example: - -```swift -SomeBuilder { - x - / y / - z -} -``` - -Today this is parsed as `SomeBuilder { x / y / z }`, however it's likely the user was expecting this to become a result builder with 3 elements, the second of which being a regex literal. - -There is currently no source compatibility impact as both cases will continue to parse as binary operations. The user may insert a `;` on the prior line to get the desired regex literal parsing. However this may not be sufficient we may need to change parsing rules (under a version check) to favor parsing regex literals in these cases. We'd like to discuss this further with the community. - -It's worth noting that this is similar to an ambiguity that already exists today with trailing closures, for example: - -```swift -SomeBuilder { - SomeType() - { print("hello") } - AnotherType() -} -``` - -`{ print("hello") }` will be parsed as a trailing closure to `SomeType()` rather than as a separate element to the result builder. - -It can also currently arise with leading dot syntax in a result builder, e.g: - -```swift -SomeBuilder { - SomeType() - .member -} -``` - -`.member` will be parsed as a member access on `SomeType()` rather than as a separate element that may have its base type inferred by the parameter of a `buildExpression` method on the result builder. - - -## Future Directions - -### Typed captures - -Typed captures would statically represent how many captures and of what kind are present in a regex literals. They could produce a `Substring` for a regular capture, `Substring?` for a zero-or-one capture, and `Array` (or a lazy collection) for a zero(or one)-or-more capture. These are worth exploring, especially in the context of the [start of variadic generics][variadics] support, but we'd like to keep this pitch and discussion focused to the details presented. - -### Other regex literals - -Multi-line extensions to regex literals is considered future work. Generally, we'd like to encourage refactoring into `Pattern` when the regex gets to that degree of complexity. - -User-specified [choice of quote delimiters][perlquotes] is considered future work. A related approach to this could be a "raw" regex literal analogous to [raw strings][rawstrings]. For example (total strawperson), an approach where `n` `#`s before the opening delimiter would requires `n` `#` at the end of the trailing delimiter as well as requiring `n-1` `#`s to access metacharacters. - -```txt -// All of the below are trying to match a path like "/tmp/foo/bar/File.app/file.txt" - -/\/tmp\/.*\/File\.app\/file\.txt/ -#//tmp/.*/File\.app/file\.txt/# -##//tmp/#.#*/File.app/file.txt/## -``` - -"Swiftier" literals, such as with non-semantic whitespace (e.g. [Raku's][rakuregex]), is future work. We'd want to strongly consider using a different backing technology for Swifty matching literals, such as PEGs. - -Fully-custom literal support, that is literals whose bodies are not parsed and there is no default type available, is orthogonal to this work. It would require support for compilation-time Swift libraries in addition to Swift APIs for the compiler and type system. - - -### Further extension to Swift language constructs - -Other language constructs, such as raw-valued enums, might benefit from further regex enhancements. - -```swift -enum CalculatorToken: Regex { - case wholeNumber = /\d+/ - case identifier = /\w+/ - case symbol = /\p{Math}/ - ... -} -``` - -As mentioned in the overview, general purpose extensions to Swift (syntactic) pattern matching could benefit regex - -```swift -func parseField(_ field: String) -> ParsedField { - switch field { - case let text <- /#\s?(.*)/: - return .comment(text) - case let (l, u) <- /([0-9A-F]+)(?:\.\.([0-9A-F]+))?/: - return .scalars(Unicode.Scalar(hex: l) ... Unicode.Scalar(hex: u ?? l)) - case let prop <- GraphemeBreakProperty.init: - return .property(prop) - } -} -``` - -### Other semantic details - -Further details about the semantics of regex literals, such as what definition we give to character classes, the initial supported feature set, and how to switch between grapheme-semantic and scalar-semantic usage, is still under investigation and outside the scope of this discussion. - -## Alternatives considered - -### Using a different delimiter to `/` - -As explored above, using `/` as the delimiter has the potential to conflict with existing operators using that character, and may necessitate: - -- Changing of parsing rules around chained `/` over multiple lines -- Deprecating prefix and postfix operators containing the `/` character -- Requiring additional whitespace to disambiguate from infix operators containing `/` -- Requiring a new language version mode to parse the literal with `/` delimiters - -However one of the main goals of this pitch is to introduce a familiar syntax for regular expression literals, which has been the motivation behind choices such as using the PCRE regex syntax. Given the fact that `/` is an existing term of art for regular expressions, we feel that if the aforementioned parsing issues can be solved in a satisfactory manner, we should prefer it as the delimiter. - - -### Reusing string literal syntax - -Instead of supporting a first-class literal kind for regular expressions, we could instead allow users to write a regular expression in a string literal, and parse, diagnose, and generate the appropriate code when it's coerced to an `ExpressibleByRegexLiteral` conforming type. - -```swift -let regex: Regex = "([[:alpha:]]\w*) = ([0-9A-F]+)" -``` - -However we decided against this because: - -- We would not be able to easily apply custom syntax highlighting for the regex syntax -- It would require an `ExpressibleByRegexLiteral` contextual type to be treated as a regex, otherwise it would be defaulted to `String`, which may be undesired -- In an overloaded context it may be ambiguous whether a string literal is meant to be interpreted as a literal string or regex -- Regex escape sequences aren't currently compatible with string literal escape sequence rules, e.g `\w` is currently illegal in a string literal -- It wouldn't be compatible with other string literal features such as interpolations - -[PCRE]: http://pcre.org/current/doc/html/pcre2syntax.html -[overview]: https://forums.swift.org/t/declarative-string-processing-overview/52459 -[variadics]: https://forums.swift.org/t/pitching-the-start-of-variadic-generics/51467 -[stringinterpolation]: https://github.com/apple/swift-evolution/blob/master/proposals/0228-fix-expressiblebystringinterpolation.md -[countable]: https://en.wikipedia.org/wiki/Countable_set -[ordering]: https://forums.swift.org/t/min-function-doesnt-work-on-values-greater-than-9-999-any-idea-why/52004/16 -[perlquotes]: https://perldoc.perl.org/perlop#Quote-and-Quote-like-Operators -[rawstrings]: https://github.com/apple/swift-evolution/blob/main/proposals/0200-raw-string-escaping.md -[rakuregex]: https://docs.raku.org/language/regexes diff --git a/Documentation/Evolution/DelimiterSyntax.md b/Documentation/Evolution/RegexLiterals.md similarity index 100% rename from Documentation/Evolution/DelimiterSyntax.md rename to Documentation/Evolution/RegexLiterals.md From ce458ebc5b2c93d6a64206310851499e37928612 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Tue, 12 Apr 2022 15:21:05 -0600 Subject: [PATCH 058/133] Nominalize API names (#271) Go from matchWhole -> wholeMatch(in:), which is more consistent with firstMatch etc. --- Documentation/Evolution/RegexTypeOverview.md | 26 ++++---- .../Participants/RegexParticipant.swift | 4 +- Sources/RegexBuilder/Match.swift | 24 ++++---- .../Algorithms/Consumers/RegexConsumer.swift | 3 +- .../Algorithms/Matching/FirstMatch.swift | 4 +- .../Algorithms/Matching/Matches.swift | 7 ++- Sources/_StringProcessing/Regex/Match.swift | 36 ++++++----- Tests/RegexBuilderTests/CustomTests.swift | 10 ++-- Tests/RegexBuilderTests/MotivationTests.swift | 2 +- Tests/RegexBuilderTests/RegexDSLTests.swift | 60 +++++++++---------- 10 files changed, 94 insertions(+), 82 deletions(-) diff --git a/Documentation/Evolution/RegexTypeOverview.md b/Documentation/Evolution/RegexTypeOverview.md index adb6640ad..bce336551 100644 --- a/Documentation/Evolution/RegexTypeOverview.md +++ b/Documentation/Evolution/RegexTypeOverview.md @@ -1,4 +1,3 @@ - # Regex Type and Overview - Authors: [Michael Ilseman](https://github.com/milseman) @@ -225,7 +224,7 @@ func processEntry(_ line: String) -> Transaction? { The result builder allows for inline failable value construction, which participates in the overall string processing algorithm: returning `nil` signals a local failure and the engine backtracks to try an alternative. This not only relieves the use site from post-processing, it enables new kinds of processing algorithms, allows for search-space pruning, and enhances debuggability. -Swift regexes describe an unambiguous algorithm, were choice is ordered and effects can be reliably observed. For example, a `print()` statement inside the `TryCapture`'s transform function will run whenever the overall algorithm naturally dictates an attempt should be made. Optimizations can only elide such calls if they can prove it is behavior-preserving (e.g. "pure"). +Swift regexes describe an unambiguous algorithm, where choice is ordered and effects can be reliably observed. For example, a `print()` statement inside the `TryCapture`'s transform function will run whenever the overall algorithm naturally dictates an attempt should be made. Optimizations can only elide such calls if they can prove it is behavior-preserving (e.g. "pure"). `CustomMatchingRegexComponent`, discussed in [String Processing Algorithms][pitches], allows industrial-strength parsers to be used a regex components. This allows us to drop the overly-permissive pre-parsing step: @@ -278,14 +277,14 @@ func processEntry(_ line: String) -> Transaction? { *Note*: Details on how references work is discussed in [Regex Builders][pitches]. `Regex.Match` supports referring to _all_ captures by position (`match.1`, etc.) whether named or referenced or neither. Due to compiler limitations, result builders do not support forming labeled tuples for named captures. -### Algorithms, algorithms everywhere +### Regex-powered algorithms Regexes can be used right out of the box with a variety of powerful and convenient algorithms, including trimming, splitting, and finding/replacing all matches within a string. These algorithms are discussed in [String Processing Algorithms][pitches]. -### Onward Unicode +### Unicode handling A regex describes an algorithm to be ran over some model of string, and Swift's `String` has a rather unique Unicode-forward model. `Character` is an [extended grapheme cluster](https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) and equality is determined under [canonical equivalence](https://www.unicode.org/reports/tr15/#Canon_Compat_Equivalence). @@ -310,12 +309,12 @@ public struct Regex { /// Match a string in its entirety. /// /// Returns `nil` if no match and throws on abort - public func matchWhole(_ s: String) throws -> Regex.Match? + public func wholeMatch(in s: String) throws -> Regex.Match? /// Match part of the string, starting at the beginning. /// /// Returns `nil` if no match and throws on abort - public func matchPrefix(_ s: String) throws -> Regex.Match? + public func prefixMatch(in s: String) throws -> Regex.Match? /// Find the first match in a string /// @@ -325,17 +324,17 @@ public struct Regex { /// Match a substring in its entirety. /// /// Returns `nil` if no match and throws on abort - public func matchWhole(_ s: Substring) throws -> Regex.Match? + public func wholeMatch(in s: Substring) throws -> Regex.Match? /// Match part of the string, starting at the beginning. /// /// Returns `nil` if no match and throws on abort - public func matchPrefix(_ s: Substring) throws -> Regex.Match? + public func prefixMatch(in s: Substring) throws -> Regex.Match? /// Find the first match in a substring /// /// Returns `nil` if no match is found and throws on abort - public func firstMatch(_ s: Substring) throws -> Regex.Match? + public func firstMatch(in s: Substring) throws -> Regex.Match? /// The result of matching a regex against a string. /// @@ -344,19 +343,19 @@ public struct Regex { @dynamicMemberLookup public struct Match { /// The range of the overall match - public let range: Range + public var range: Range { get } /// The produced output from the match operation - public var output: Output + public var output: Output { get } /// Lookup a capture by name or number - public subscript(dynamicMember keyPath: KeyPath) -> T + public subscript(dynamicMember keyPath: KeyPath) -> T { get } /// Lookup a capture by number @_disfavoredOverload public subscript( dynamicMember keyPath: KeyPath<(Output, _doNotUse: ()), Output> - ) -> Output + ) -> Output { get } // Note: this allows `.0` when `Match` is not a tuple. } @@ -482,6 +481,7 @@ We're also looking for more community discussion on what the default type system The actual `Match` struct just stores ranges: the `Substrings` are lazily created on demand. This avoids unnecessary ARC traffic and memory usage. + ### `Regex` instead of `Regex` The generic parameter `Output` is proposed to contain both the whole match (the `.0` element if `Output` is a tuple) and captures. One alternative we have considered is separating `Output` into the entire match and the captures, i.e. `Regex`, and using `Void` for for `Captures` when there are no captures. diff --git a/Sources/Exercises/Participants/RegexParticipant.swift b/Sources/Exercises/Participants/RegexParticipant.swift index 71018d8a7..6fddc0914 100644 --- a/Sources/Exercises/Participants/RegexParticipant.swift +++ b/Sources/Exercises/Participants/RegexParticipant.swift @@ -63,7 +63,7 @@ private func graphemeBreakPropertyData( forLine line: String, using regex: RP ) -> GraphemeBreakEntry? where RP.Output == (Substring, Substring, Substring?, Substring) { - line.matchWhole(regex).map(\.output).flatMap(extractFromCaptures) + line.wholeMatch(of: regex).map(\.output).flatMap(extractFromCaptures) } private func graphemeBreakPropertyDataLiteral( @@ -80,7 +80,7 @@ private func graphemeBreakPropertyDataLiteral( private func graphemeBreakPropertyData( forLine line: String ) -> GraphemeBreakEntry? { - line.matchWhole { + line.wholeMatch { TryCapture(OneOrMore(.hexDigit)) { Unicode.Scalar(hex: $0) } Optionally { ".." diff --git a/Sources/RegexBuilder/Match.swift b/Sources/RegexBuilder/Match.swift index ac07ec0b8..e6718d96b 100644 --- a/Sources/RegexBuilder/Match.swift +++ b/Sources/RegexBuilder/Match.swift @@ -12,29 +12,29 @@ import _StringProcessing extension String { - public func matchWhole( - @RegexComponentBuilder _ content: () -> R + public func wholeMatch( + @RegexComponentBuilder of content: () -> R ) -> Regex.Match? { - matchWhole(content()) + wholeMatch(of: content()) } - public func matchPrefix( - @RegexComponentBuilder _ content: () -> R + public func prefixMatch( + @RegexComponentBuilder of content: () -> R ) -> Regex.Match? { - matchPrefix(content()) + prefixMatch(of: content()) } } extension Substring { - public func matchWhole( - @RegexComponentBuilder _ content: () -> R + public func wholeMatch( + @RegexComponentBuilder of content: () -> R ) -> Regex.Match? { - matchWhole(content()) + wholeMatch(of: content()) } - public func matchPrefix( - @RegexComponentBuilder _ content: () -> R + public func prefixMatch( + @RegexComponentBuilder of content: () -> R ) -> Regex.Match? { - matchPrefix(content()) + prefixMatch(of: content()) } } diff --git a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift index dcc5d9f2b..2718d520a 100644 --- a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift +++ b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift @@ -9,6 +9,7 @@ // //===----------------------------------------------------------------------===// +// FIXME: What even is this? Can we delete this whole thing? struct RegexConsumer< R: RegexComponent, Consumed: BidirectionalCollection > where Consumed.SubSequence == Substring { @@ -24,7 +25,7 @@ extension RegexConsumer { func _matchingConsuming( _ consumed: Substring, in range: Range ) -> (upperBound: String.Index, match: Match)? { - guard let result = try! regex._match( + guard let result = try! regex.regex._match( consumed.base, in: range, mode: .partialFromFront ) else { return nil } diff --git a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift index 2aea0f342..1ad555e7d 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift @@ -55,9 +55,9 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: The first match of `regex` in the collection, or `nil` if /// there isn't a match. public func firstMatch( - of regex: R + of r: R ) -> Regex.Match? { let slice = self[...] - return try? regex.firstMatch(in: slice.base) + return try? r.regex.firstMatch(in: slice.base) } } diff --git a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift index 6453fccb0..24cdbee0f 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift @@ -202,14 +202,17 @@ extension BidirectionalCollection where SubSequence == Substring { // FIXME: Replace the returned value as `some Collection.Match> // when SE-0346 is enabled - func _matches(of regex: R) -> [Regex.Match] { + func _matches(of r: R) -> [Regex.Match] { let slice = self[...] var start = self.startIndex let end = self.endIndex + let regex = r.regex var result = [Regex.Match]() while start < end { - guard let match = try? regex._firstMatch(slice.base, in: start.. Regex.Match? { + public func wholeMatch(in s: String) throws -> Regex.Match? { try _match(s, in: s.startIndex.. Regex.Match? { + public func prefixMatch(in s: String) throws -> Regex.Match? { try _match(s, in: s.startIndex.. Regex.Match? { + public func wholeMatch(in s: Substring) throws -> Regex.Match? { try _match(s.base, in: s.startIndex.. Regex.Match? { + public func prefixMatch(in s: Substring) throws -> Regex.Match? { try _match(s.base, in: s.startIndex..(_ regex: R) -> Regex.Match? { - try? regex.matchWhole(self) + public func wholeMatch( + of r: R + ) -> Regex.Match? { + try? r.regex.wholeMatch(in: self) } - public func matchPrefix(_ regex: R) -> Regex.Match? { - try? regex.matchPrefix(self) + public func prefixMatch( + of r: R + ) -> Regex.Match? { + try? r.regex.prefixMatch(in: self) } } extension Substring { - public func matchWhole(_ regex: R) -> Regex.Match? { - try? regex.matchWhole(self) - } - public func matchPrefix(_ regex: R) -> Regex.Match? { - try? regex.matchPrefix(self) + public func wholeMatch( + of r: R + ) -> Regex.Match? { + try? r.regex.wholeMatch(in: self) + } + public func prefixMatch( + of r: R + ) -> Regex.Match? { + try? r.regex.prefixMatch(in: self) } } diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index 79ebc2693..555ecb8ca 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -62,7 +62,7 @@ func customTest( let result: Match? switch call { case .match: - result = input.matchWhole(regex)?.output + result = input.wholeMatch(of: regex)?.output case .firstMatch: result = input.firstMatch(of: regex)?.output } @@ -167,7 +167,7 @@ class CustomRegexComponentTests: XCTestCase { // TODO: Why is Radix optional? do { - guard let m = try hexRegex.matchWhole("123aef.345") else { + guard let m = try hexRegex.wholeMatch(in: "123aef.345") else { XCTFail() return } @@ -180,7 +180,7 @@ class CustomRegexComponentTests: XCTestCase { } do { - _ = try hexRegex.matchWhole("123aef❗️345") + _ = try hexRegex.wholeMatch(in: "123aef❗️345") XCTFail() } catch let e as Abort { XCTAssertEqual(e, Abort()) @@ -202,7 +202,7 @@ class CustomRegexComponentTests: XCTestCase { } do { - guard let m = try addressRegex.matchWhole("0x1234567f") else { + guard let m = try addressRegex.wholeMatch(in: "0x1234567f") else { XCTFail() return } @@ -213,7 +213,7 @@ class CustomRegexComponentTests: XCTestCase { } do { - _ = try addressRegex.matchWhole("0xdeadbeef") + _ = try addressRegex.wholeMatch(in: "0xdeadbeef") XCTFail() } catch let e as Poison { XCTAssertEqual(e, Poison()) diff --git a/Tests/RegexBuilderTests/MotivationTests.swift b/Tests/RegexBuilderTests/MotivationTests.swift index 882ba6448..1927b9ae4 100644 --- a/Tests/RegexBuilderTests/MotivationTests.swift +++ b/Tests/RegexBuilderTests/MotivationTests.swift @@ -199,7 +199,7 @@ private func process( _ line: String, using regex: Regex<(Substring, Substring, Substring, Substring, Substring)> ) -> Transaction? { - guard let output = try? regex.matchWhole(line), + guard let output = try? regex.wholeMatch(in: line), let kind = Transaction.Kind(output.1) else { return nil diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 1f5305c59..0c0bf7c8f 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -24,7 +24,7 @@ class RegexDSLTests: XCTestCase { ) throws { let regex = content() for (input, maybeExpectedCaptures) in tests { - let maybeMatch = input.matchWhole(regex) + let maybeMatch = input.wholeMatch(of: regex) if let expectedCaptures = maybeExpectedCaptures { let match = try XCTUnwrap(maybeMatch, file: file, line: line) XCTAssertTrue( @@ -52,12 +52,12 @@ class RegexDSLTests: XCTestCase { } // Assert the inferred capture type. let _: (Substring, Substring, Int).Type = type(of: regex).Output.self - let maybeMatch = "ab1".matchWhole(regex) + let maybeMatch = "ab1".wholeMatch(of: regex) let match = try XCTUnwrap(maybeMatch) XCTAssertTrue(match.output == ("ab1", "b", 1)) let substring = "ab1"[...] - let substringMatch = try XCTUnwrap(substring.matchWhole(regex)) + let substringMatch = try XCTUnwrap(substring.wholeMatch(of: regex)) XCTAssertTrue(match.output == substringMatch.output) } @@ -126,7 +126,7 @@ class RegexDSLTests: XCTestCase { } func testMatchResultDotZeroWithoutCapture() throws { - let match = try XCTUnwrap("aaa".matchWhole { OneOrMore { "a" } }) + let match = try XCTUnwrap("aaa".wholeMatch { OneOrMore { "a" } }) XCTAssertEqual(match.0, "aaa") } @@ -135,8 +135,8 @@ class RegexDSLTests: XCTestCase { let regex = ChoiceOf { "aaa" } - XCTAssertTrue("aaa".matchWhole(regex)?.output == "aaa") - XCTAssertNil("aab".matchWhole(regex)?.output) + XCTAssertTrue("aaa".wholeMatch(of: regex)?.output == "aaa") + XCTAssertNil("aab".wholeMatch(of: regex)?.output) } do { let regex = ChoiceOf { @@ -144,10 +144,10 @@ class RegexDSLTests: XCTestCase { "bbb" "ccc" } - XCTAssertTrue("aaa".matchWhole(regex)?.output == "aaa") - XCTAssertNil("aab".matchWhole(regex)?.output) - XCTAssertTrue("bbb".matchWhole(regex)?.output == "bbb") - XCTAssertTrue("ccc".matchWhole(regex)?.output == "ccc") + XCTAssertTrue("aaa".wholeMatch(of: regex)?.output == "aaa") + XCTAssertNil("aab".wholeMatch(of: regex)?.output) + XCTAssertTrue("bbb".wholeMatch(of: regex)?.output == "bbb") + XCTAssertTrue("ccc".wholeMatch(of: regex)?.output == "ccc") } do { let regex = Regex { @@ -162,7 +162,7 @@ class RegexDSLTests: XCTestCase { } } XCTAssertTrue( - try XCTUnwrap("abc".matchWhole(regex)?.output) == ("abc", "c")) + try XCTUnwrap("abc".wholeMatch(of: regex)?.output) == ("abc", "c")) } do { let regex = ChoiceOf { @@ -170,18 +170,18 @@ class RegexDSLTests: XCTestCase { "bbb" "ccc" } - XCTAssertTrue("aaa".matchWhole(regex)?.output == "aaa") - XCTAssertNil("aab".matchWhole(regex)?.output) - XCTAssertTrue("bbb".matchWhole(regex)?.output == "bbb") - XCTAssertTrue("ccc".matchWhole(regex)?.output == "ccc") + XCTAssertTrue("aaa".wholeMatch(of: regex)?.output == "aaa") + XCTAssertNil("aab".wholeMatch(of: regex)?.output) + XCTAssertTrue("bbb".wholeMatch(of: regex)?.output == "bbb") + XCTAssertTrue("ccc".wholeMatch(of: regex)?.output == "ccc") } do { let regex = ChoiceOf { Capture("aaa") } XCTAssertTrue( - try XCTUnwrap("aaa".matchWhole(regex)?.output) == ("aaa", "aaa")) - XCTAssertNil("aab".matchWhole(regex)?.output) + try XCTUnwrap("aaa".wholeMatch(of: regex)?.output) == ("aaa", "aaa")) + XCTAssertNil("aab".wholeMatch(of: regex)?.output) } do { let regex = ChoiceOf { @@ -190,12 +190,12 @@ class RegexDSLTests: XCTestCase { Capture("ccc") } XCTAssertTrue( - try XCTUnwrap("aaa".matchWhole(regex)?.output) == ("aaa", "aaa", nil, nil)) + try XCTUnwrap("aaa".wholeMatch(of: regex)?.output) == ("aaa", "aaa", nil, nil)) XCTAssertTrue( - try XCTUnwrap("bbb".matchWhole(regex)?.output) == ("bbb", nil, "bbb", nil)) + try XCTUnwrap("bbb".wholeMatch(of: regex)?.output) == ("bbb", nil, "bbb", nil)) XCTAssertTrue( - try XCTUnwrap("ccc".matchWhole(regex)?.output) == ("ccc", nil, nil, "ccc")) - XCTAssertNil("aab".matchWhole(regex)?.output) + try XCTUnwrap("ccc".wholeMatch(of: regex)?.output) == ("ccc", nil, nil, "ccc")) + XCTAssertNil("aab".wholeMatch(of: regex)?.output) } } @@ -407,7 +407,7 @@ class RegexDSLTests: XCTestCase { // Assert the inferred capture type. let _: Substring.Type = type(of: regex).Output.self let input = "123123" - let match = try XCTUnwrap(input.matchWhole(regex)?.output) + let match = try XCTUnwrap(input.wholeMatch(of: regex)?.output) XCTAssertTrue(match == input) } @@ -534,7 +534,7 @@ class RegexDSLTests: XCTestCase { let unicodeLine = "1BCA0..1BCA3 ; Control # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP" - let match = try XCTUnwrap(unicodeLine.matchWhole(unicodeData)) + let match = try XCTUnwrap(unicodeLine.wholeMatch(of: unicodeData)) XCTAssertEqual(match.0, Substring(unicodeLine)) XCTAssertEqual(match.1, "Control") } @@ -566,7 +566,7 @@ class RegexDSLTests: XCTestCase { Substring, Unicode.Scalar?, Unicode.Scalar??, Substring ) let _: ExpectedMatch.Type = type(of: regexWithCapture).Output.self - let maybeMatchResult = line.matchWhole(regexWithCapture) + let maybeMatchResult = line.wholeMatch(of: regexWithCapture) let matchResult = try XCTUnwrap(maybeMatchResult) let (wholeMatch, lower, upper, propertyString) = matchResult.output XCTAssertEqual(wholeMatch, Substring(line)) @@ -601,7 +601,7 @@ class RegexDSLTests: XCTestCase { Substring, Unicode.Scalar, Unicode.Scalar?, Substring ) let _: ExpectedMatch.Type = type(of: regexWithTryCapture).Output.self - let maybeMatchResult = line.matchWhole(regexWithTryCapture) + let maybeMatchResult = line.wholeMatch(of: regexWithTryCapture) let matchResult = try XCTUnwrap(maybeMatchResult) let (wholeMatch, lower, upper, propertyString) = matchResult.output XCTAssertEqual(wholeMatch, Substring(line)) @@ -614,7 +614,7 @@ class RegexDSLTests: XCTestCase { let regexLiteral = try Regex( compiling: #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, as: (Substring, Substring, Substring?, Substring).self) - let maybeMatchResult = line.matchWhole(regexLiteral) + let maybeMatchResult = line.wholeMatch(of: regexLiteral) let matchResult = try XCTUnwrap(maybeMatchResult) let (wholeMatch, lower, upper, propertyString) = matchResult.output XCTAssertEqual(wholeMatch, Substring(line)) @@ -628,7 +628,7 @@ class RegexDSLTests: XCTestCase { do { let regex = try Regex(compiling: "aabcc.") let line = "aabccd" - let match = try XCTUnwrap(line.matchWhole(regex)) + let match = try XCTUnwrap(line.wholeMatch(of: regex)) XCTAssertEqual(match.0, line[...]) let output = match.output XCTAssertEqual(output[0].substring, line[...]) @@ -640,7 +640,7 @@ class RegexDSLTests: XCTestCase { A6F0..A6F1 ; Extend # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM \ COMBINING MARK TUKWENTIS """ - let match = try XCTUnwrap(line.matchWhole(regex)) + let match = try XCTUnwrap(line.wholeMatch(of: regex)) XCTAssertEqual(match.0, line[...]) let output = match.output XCTAssertEqual(output[0].substring, line[...]) @@ -705,7 +705,7 @@ class RegexDSLTests: XCTestCase { } } let input = "abc#41#42abc#42#42" - let result = try XCTUnwrap(input.matchWhole(regex)) + let result = try XCTUnwrap(input.wholeMatch(of: regex)) XCTAssertEqual(result[a], "abc") XCTAssertEqual(result[b], 42) } @@ -785,7 +785,7 @@ class RegexDSLTests: XCTestCase { let parser = SemanticVersionParser() for (str, version) in versions { - XCTAssertEqual(str.matchWhole(parser)?.output, version) + XCTAssertEqual(str.wholeMatch(of: parser)?.output, version) } } } From 657c4a6617da007fdf8f47c0b7ffc99ec22a8d9a Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 13 Apr 2022 15:25:56 +0100 Subject: [PATCH 059/133] Allow POSIX character properties outside of custom character classes This matches the ICU behavior, and appears to be suggested by UTS#18. --- .../Regex/Parse/LexicalAnalysis.swift | 17 +++++++---------- Sources/_RegexParser/Regex/Parse/Parse.swift | 4 ++-- .../_StringProcessing/Utility/ASTBuilder.swift | 5 +++++ Tests/RegexTests/ParseTests.swift | 11 ++++++++--- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift index bf53d0ab1..f70989c9f 100644 --- a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift +++ b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift @@ -1064,14 +1064,13 @@ extension Source { } mutating func lexCustomCCStart( - context: ParsingContext ) throws -> Located? { recordLoc { src in // Make sure we don't have a POSIX character property. This may require // walking to its ending to make sure we have a closing ':]', as otherwise // we have a custom character class. // TODO: This behavior seems subtle, could we warn? - guard !src.canLexPOSIXCharacterProperty(context: context) else { + guard !src.canLexPOSIXCharacterProperty() else { return nil } if src.tryEat("[") { @@ -1104,11 +1103,8 @@ extension Source { } private mutating func lexPOSIXCharacterProperty( - context: ParsingContext ) throws -> Located? { - // Only allowed in a custom character class. - guard context.isInCustomCharacterClass else { return nil } - return try recordLoc { src in + try recordLoc { src in try src.tryEating { src in guard src.tryEat(sequence: "[:") else { return nil } let inverted = src.tryEat("^") @@ -1127,10 +1123,10 @@ extension Source { } } - private func canLexPOSIXCharacterProperty(context: ParsingContext) -> Bool { + private func canLexPOSIXCharacterProperty() -> Bool { do { var src = self - return try src.lexPOSIXCharacterProperty(context: context) != nil + return try src.lexPOSIXCharacterProperty() != nil } catch { // We want to tend on the side of lexing a POSIX character property, so // even if it is invalid in some way (e.g invalid property names), still @@ -1818,8 +1814,9 @@ extension Source { if !customCC && (src.peek() == ")" || src.peek() == "|") { return nil } // TODO: Store customCC in the atom, if that's useful - // POSIX character property. - if let prop = try src.lexPOSIXCharacterProperty(context: context)?.value { + // POSIX character property. Like \p{...} this is also allowed outside of + // a custom character class. + if let prop = try src.lexPOSIXCharacterProperty()?.value { return .property(prop) } diff --git a/Sources/_RegexParser/Regex/Parse/Parse.swift b/Sources/_RegexParser/Regex/Parse/Parse.swift index d70a1f14f..c3aa3500b 100644 --- a/Sources/_RegexParser/Regex/Parse/Parse.swift +++ b/Sources/_RegexParser/Regex/Parse/Parse.swift @@ -403,7 +403,7 @@ extension Parser { } // Check if we have the start of a custom character class '['. - if let cccStart = try source.lexCustomCCStart(context: context) { + if let cccStart = try source.lexCustomCCStart() { return .customCharacterClass( try parseCustomCharacterClass(cccStart)) } @@ -487,7 +487,7 @@ extension Parser { while source.peek() != "]" && source.peekCCBinOp() == nil { // Nested custom character class. - if let cccStart = try source.lexCustomCCStart(context: context) { + if let cccStart = try source.lexCustomCCStart() { members.append(.custom(try parseCustomCharacterClass(cccStart))) continue } diff --git a/Sources/_StringProcessing/Utility/ASTBuilder.swift b/Sources/_StringProcessing/Utility/ASTBuilder.swift index 7a8edcd24..107a3e3c9 100644 --- a/Sources/_StringProcessing/Utility/ASTBuilder.swift +++ b/Sources/_StringProcessing/Utility/ASTBuilder.swift @@ -354,6 +354,11 @@ func prop( ) -> AST.Node { atom(.property(.init(kind, isInverted: inverted, isPOSIX: false))) } +func posixProp( + _ kind: AST.Atom.CharacterProperty.Kind, inverted: Bool = false +) -> AST.Node { + atom(.property(.init(kind, isInverted: inverted, isPOSIX: true))) +} // Raw atom constructing variant func atom_a( diff --git a/Tests/RegexTests/ParseTests.swift b/Tests/RegexTests/ParseTests.swift index aa0ebbf98..e9b422379 100644 --- a/Tests/RegexTests/ParseTests.swift +++ b/Tests/RegexTests/ParseTests.swift @@ -477,12 +477,9 @@ extension RegexTests { // These are custom character classes, not invalid POSIX character classes. // TODO: This behavior is subtle, we ought to warn. parseTest("[[:space]]", charClass(charClass(":", "s", "p", "a", "c", "e"))) - parseTest("[:space:]", charClass(":", "s", "p", "a", "c", "e", ":")) parseTest("[:a]", charClass(":", "a")) parseTest("[a:]", charClass("a", ":")) parseTest("[:]", charClass(":")) - parseTest("[::]", charClass(":", ":")) - parseTest("[:=:]", charClass(":", "=", ":")) parseTest("[[:]]", charClass(charClass(":"))) parseTest("[[:a=b=c:]]", charClass(charClass(":", "a", "=", "b", "=", "c", ":"))) @@ -522,6 +519,12 @@ extension RegexTests { posixProp_m(.binary(.uppercase), inverted: true), "c", "d")) + // Like ICU, we allow POSIX character properties outside of custom character + // classes. This also appears to be suggested by UTS#18. + // TODO: We should likely emit a warning. + parseTest("[:space:]", posixProp(.binary(.whitespace))) + parseTest("[:script=Greek:]", posixProp(.script(.greek))) + parseTest("[[[:space:]]]", charClass(charClass( posixProp_m(.binary(.whitespace)) ))) @@ -2252,6 +2255,8 @@ extension RegexTests { diagnosticTest("[[:a:", .expected("]")) diagnosticTest("[[:a[:]", .expected("]")) + diagnosticTest("[::]", .emptyProperty) + diagnosticTest("[:=:]", .emptyProperty) diagnosticTest("[[::]]", .emptyProperty) diagnosticTest("[[:=:]]", .emptyProperty) From 81ce4efc095b0d70782b8210a3ded46e856854c2 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 13 Apr 2022 20:41:58 +0100 Subject: [PATCH 060/133] Update RegexLiterals.md --- Documentation/Evolution/RegexLiterals.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Evolution/RegexLiterals.md b/Documentation/Evolution/RegexLiterals.md index 3a9d02a8b..29e1cfd35 100644 --- a/Documentation/Evolution/RegexLiterals.md +++ b/Documentation/Evolution/RegexLiterals.md @@ -301,7 +301,7 @@ However, such a syntax would lose out on the familiarity benefits of standard re ## Alternatives Considered -Given the fact that `/.../` is an existing term of art for regular expressions, we feel it should be the preferred delimiter syntax. It should be noted that the syntax has become less popular in some communities such as Perl, however we still feel that it is a compelling choice, especially with extended delimiters `#/.../#`. Additionally, while there has some syntactic ambiguities, we do not feel that they are sufficient to disqualify the syntax. To evaluate this trade-off, below is a list of alternative delimiters that would not have the same ambiguities. +Given the fact that `/.../` is an existing term of art for regular expressions, we feel it should be the preferred delimiter syntax. It should be noted that the syntax has become less popular in some communities such as Perl, however we still feel that it is a compelling choice, especially with extended delimiters `#/.../#`. Additionally, while there has some syntactic ambiguities, we do not feel that they are sufficient to disqualify the syntax. To evaluate this trade-off, below is a list of alternative delimiters that would not have the same ambiguities, and would not therefore require source breaking changes. ### Prefixed quote `re'...'` From 859c3d5fc8263b610b4611f968c6ebb7f56654bc Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 14 Apr 2022 10:42:11 +0100 Subject: [PATCH 061/133] Update RegexLiterals.md Fix a dead link and example. --- Documentation/Evolution/RegexLiterals.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/Evolution/RegexLiterals.md b/Documentation/Evolution/RegexLiterals.md index 29e1cfd35..3c12c9c7a 100644 --- a/Documentation/Evolution/RegexLiterals.md +++ b/Documentation/Evolution/RegexLiterals.md @@ -75,7 +75,7 @@ func matchHexAssignment(_ input: String) -> (String, Int)? { let hex = Int(match.hex, radix: 16) else { return nil } - return (match.identifier, hex) + return (String(match.identifier), hex) } ``` @@ -382,8 +382,8 @@ We therefore feel this would be a much less compelling feature without first cla [regex-type]: https://github.com/apple/swift-evolution/blob/main/proposals/0350-regex-type-overview.md [strongly-typed-captures]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/StronglyTypedCaptures.md -[internal-syntax]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntax.md -[extended-regex-syntax]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntax.md#extended-syntax-modes +[internal-syntax]: https://github.com/apple/swift-experimental-string-processing/blob/39cb22d96d90ee7cb308b1153e106e50598afdd9/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md +[extended-regex-syntax]: https://github.com/apple/swift-experimental-string-processing/blob/39cb22d96d90ee7cb308b1153e106e50598afdd9/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md#extended-syntax-modes [regex-dsl]: https://github.com/apple/swift-evolution/blob/main/proposals/0351-regex-builder.md [dsl-captures]: https://github.com/apple/swift-evolution/blob/main/proposals/0351-regex-builder.md#capture-and-reference From 33b0b4ccd40e2eb37be2b46163137354956b8d14 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 14 Apr 2022 12:27:20 +0100 Subject: [PATCH 062/133] Fix character class trivia matching Rather than matching and not advancing the input, we should always return `nil` to never match against the trivia. --- Sources/_StringProcessing/ConsumerInterface.swift | 5 +---- Tests/RegexTests/MatchTests.swift | 10 ++++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Sources/_StringProcessing/ConsumerInterface.swift b/Sources/_StringProcessing/ConsumerInterface.swift index b343862ef..49e459c0b 100644 --- a/Sources/_StringProcessing/ConsumerInterface.swift +++ b/Sources/_StringProcessing/ConsumerInterface.swift @@ -287,11 +287,8 @@ extension DSLTree.CustomCharacterClass.Member { } case .trivia: // TODO: Should probably strip this earlier... - return { _, bounds in - return bounds.lowerBound - } + return { _, _ in nil } } - } } diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index f1074c033..05162a9f5 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -1208,6 +1208,16 @@ extension RegexTests { ("CaFe", true), ("EfAc", true)) } + + func testNonSemanticWhitespace() { + firstMatchTest(#" \t "#, input: " \t ", match: " \t ") + firstMatchTest(#"(?xx) \t "#, input: " \t ", match: "\t") + + firstMatchTest(#"[ \t]+"#, input: " \t ", match: " \t ") + firstMatchTest(#"(?xx)[ \t]+"#, input: " \t ", match: "\t") + firstMatchTest(#"(?xx)[ \t]+"#, input: " \t\t ", match: "\t\t") + firstMatchTest(#"(?xx)[ \t]+"#, input: " \t \t", match: "\t") + } func testASCIIClasses() { // 'D' ASCII-only digits From 70ecb27ab216d0453df2227c6809859118b169cd Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 14 Apr 2022 12:27:21 +0100 Subject: [PATCH 063/133] Fix trivia parsing for set operations and initial `]` cases Previously we would check for an empty array of members when deciding whether an initial `]` is literal, or if the operands of a set operation are invalid. Switch to checking whether we have any semantic members instead. --- .../Regex/AST/CustomCharClass.swift | 6 ++- Sources/_RegexParser/Regex/Parse/Parse.swift | 29 ++++++----- .../_RegexParser/Regex/Printing/DumpAST.swift | 4 +- Tests/RegexTests/MatchTests.swift | 3 ++ Tests/RegexTests/ParseTests.swift | 49 +++++++++++++++++-- 5 files changed, 73 insertions(+), 18 deletions(-) diff --git a/Sources/_RegexParser/Regex/AST/CustomCharClass.swift b/Sources/_RegexParser/Regex/AST/CustomCharClass.swift index 614048f0a..19e72aef5 100644 --- a/Sources/_RegexParser/Regex/AST/CustomCharClass.swift +++ b/Sources/_RegexParser/Regex/AST/CustomCharClass.swift @@ -97,6 +97,10 @@ extension CustomCC.Member { if case .trivia = self { return true } return false } + + public var isSemantic: Bool { + !isTrivia + } } extension AST.CustomCharacterClass { @@ -104,7 +108,7 @@ extension AST.CustomCharacterClass { /// nested custom character classes. public var strippingTriviaShallow: Self { var copy = self - copy.members = copy.members.filter { !$0.isTrivia } + copy.members = copy.members.filter(\.isSemantic) return copy } } diff --git a/Sources/_RegexParser/Regex/Parse/Parse.swift b/Sources/_RegexParser/Regex/Parse/Parse.swift index c3aa3500b..b24097b83 100644 --- a/Sources/_RegexParser/Regex/Parse/Parse.swift +++ b/Sources/_RegexParser/Regex/Parse/Parse.swift @@ -438,16 +438,18 @@ extension Parser { defer { context.isInCustomCharacterClass = alreadyInCCC } typealias Member = CustomCC.Member - try source.expectNonEmpty() - var members: Array = [] + try parseCCCMembers(into: &members) - // We can eat an initial ']', as PCRE, Oniguruma, and ICU forbid empty - // character classes, and assume an initial ']' is literal. - if let loc = source.tryEatWithLoc("]") { - members.append(.atom(.init(.char("]"), loc))) + // If we didn't parse any semantic members, we can eat a ']' character, as + // PCRE, Oniguruma, and ICU forbid empty character classes, and assume an + // initial ']' is literal. + if members.none(\.isSemantic) { + if let loc = source.tryEatWithLoc("]") { + members.append(.atom(.init(.char("]"), loc))) + try parseCCCMembers(into: &members) + } } - try parseCCCMembers(into: &members) // If we have a binary set operator, parse it and the next members. Note // that this means we left associate for a chain of operators. @@ -458,8 +460,9 @@ extension Parser { var rhs: Array = [] try parseCCCMembers(into: &rhs) - if members.isEmpty || rhs.isEmpty { - throw ParseError.expectedCustomCharacterClassMembers + if members.none(\.isSemantic) || rhs.none(\.isSemantic) { + throw Source.LocatedError( + ParseError.expectedCustomCharacterClassMembers, start.location) } // If we're done, bail early @@ -472,8 +475,9 @@ extension Parser { // Otherwise it's just another member to accumulate members = [setOp] } - if members.isEmpty { - throw ParseError.expectedCustomCharacterClassMembers + if members.none(\.isSemantic) { + throw Source.LocatedError( + ParseError.expectedCustomCharacterClassMembers, start.location) } try source.expect("]") return CustomCC(start, members, loc(start.location.start)) @@ -484,7 +488,8 @@ extension Parser { ) throws { // Parse members until we see the end of the custom char class or an // operator. - while source.peek() != "]" && source.peekCCBinOp() == nil { + while !source.isEmpty && source.peek() != "]" && + source.peekCCBinOp() == nil { // Nested custom character class. if let cccStart = try source.lexCustomCCStart() { diff --git a/Sources/_RegexParser/Regex/Printing/DumpAST.swift b/Sources/_RegexParser/Regex/Printing/DumpAST.swift index 0e40ad2ce..986f3d86e 100644 --- a/Sources/_RegexParser/Regex/Printing/DumpAST.swift +++ b/Sources/_RegexParser/Regex/Printing/DumpAST.swift @@ -312,7 +312,9 @@ extension AST.CustomCharacterClass.Member: _ASTPrintable { case .quote(let q): return "\(q)" case .trivia(let t): return "\(t)" case .setOperation(let lhs, let op, let rhs): - return "op \(lhs) \(op.value) \(rhs)" + // TODO: We should eventually have some way of filtering out trivia for + // tests, so that it can appear in regular dumps. + return "op \(lhs.filter(\.isSemantic)) \(op.value) \(rhs.filter(\.isSemantic))" } } } diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index 05162a9f5..448ff3211 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -1217,6 +1217,9 @@ extension RegexTests { firstMatchTest(#"(?xx)[ \t]+"#, input: " \t ", match: "\t") firstMatchTest(#"(?xx)[ \t]+"#, input: " \t\t ", match: "\t\t") firstMatchTest(#"(?xx)[ \t]+"#, input: " \t \t", match: "\t") + + firstMatchTest("(?xx)[ a && ab ]+", input: " aaba ", match: "aa") + firstMatchTest("(?xx)[ ] a ]+", input: " a]]a ] ", match: "a]]a") } func testASCIIClasses() { diff --git a/Tests/RegexTests/ParseTests.swift b/Tests/RegexTests/ParseTests.swift index e9b422379..65dd6ed09 100644 --- a/Tests/RegexTests/ParseTests.swift +++ b/Tests/RegexTests/ParseTests.swift @@ -460,9 +460,25 @@ extension RegexTests { parseTest("[-]", charClass("-")) - // Empty character classes are forbidden, therefore this is a character - // class of literal ']'. + // Empty character classes are forbidden, therefore these are character + // classes containing literal ']'. parseTest("[]]", charClass("]")) + parseTest("[]a]", charClass("]", "a")) + parseTest( + "(?x)[ ]]", changeMatchingOptions( + matchingOptions(adding: .extended), isIsolated: true, + charClass("]")) + ) + parseTest( + "(?x)[ ] ]", changeMatchingOptions( + matchingOptions(adding: .extended), isIsolated: true, + charClass("]")) + ) + parseTest( + "(?x)[ ] a ]", changeMatchingOptions( + matchingOptions(adding: .extended), isIsolated: true, + charClass("]", "a")) + ) // These are metacharacters in certain contexts, but normal characters // otherwise. @@ -613,6 +629,16 @@ extension RegexTests { parseTest( "~~*", concat("~", zeroOrMore(of: "~"))) + parseTest( + "[ && ]", charClass( + .setOperation([" "], .init(faking: .intersection), [" ", " "])) + ) + parseTest( + "(?x)[ a && b ]", changeMatchingOptions( + matchingOptions(adding: .extended), isIsolated: true, charClass( + .setOperation(["a"], .init(faking: .intersection), ["b"])) + )) + // MARK: Quotes parseTest( @@ -2205,6 +2231,9 @@ extension RegexTests { diagnosticTest(")))", .unbalancedEndOfGroup) diagnosticTest("())()", .unbalancedEndOfGroup) + diagnosticTest("[", .expectedCustomCharacterClassMembers) + diagnosticTest("[^", .expectedCustomCharacterClassMembers) + diagnosticTest(#"\u{5"#, .expected("}")) diagnosticTest(#"\x{5"#, .expected("}")) diagnosticTest(#"\N{A"#, .expected("}")) @@ -2245,9 +2274,21 @@ extension RegexTests { diagnosticTest("(?")) diagnosticTest("(?", .expected(")")) - // The first ']' of a custom character class is literal, so this is missing - // the closing bracket. + // MARK: Character classes + + diagnosticTest("[a", .expected("]")) + + // The first ']' of a custom character class is literal, so these are + // missing the closing bracket. diagnosticTest("[]", .expected("]")) + diagnosticTest("(?x)[ ]", .expected("]")) + + diagnosticTest("[&&]", .expectedCustomCharacterClassMembers) + diagnosticTest("[a&&]", .expectedCustomCharacterClassMembers) + diagnosticTest("[&&a]", .expectedCustomCharacterClassMembers) + diagnosticTest("(?x)[ && ]", .expectedCustomCharacterClassMembers) + diagnosticTest("(?x)[ &&a]", .expectedCustomCharacterClassMembers) + diagnosticTest("(?x)[a&& ]", .expectedCustomCharacterClassMembers) diagnosticTest("[:a", .expected("]")) diagnosticTest("[:a:", .expected("]")) From a487e9494bb0a10522dc2c3a92b649fb41c2f499 Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Thu, 14 Apr 2022 11:04:10 -0700 Subject: [PATCH 064/133] Add SwiftStdlib 5.7 availability (#276) Add availability to public, SPI, and test symbols. --- Package.swift | 33 ++++++++++++++----- Sources/RegexBuilder/Anchor.swift | 2 ++ Sources/RegexBuilder/Builder.swift | 1 + Sources/RegexBuilder/CharacterClass.swift | 3 ++ Sources/RegexBuilder/DSL.swift | 11 +++++++ Sources/RegexBuilder/Match.swift | 4 +++ .../Algorithms/Algorithms/Contains.swift | 2 ++ .../Algorithms/Algorithms/FirstRange.swift | 3 ++ .../Algorithms/Algorithms/Replace.swift | 6 ++++ .../Algorithms/Algorithms/StartsWith.swift | 1 + .../Algorithms/Algorithms/Trim.swift | 7 ++++ .../Algorithms/Matching/MatchReplace.swift | 3 ++ .../Regex/AnyRegexOutput.swift | 1 + Sources/_StringProcessing/Regex/Core.swift | 2 ++ .../Regex/DSLConsumers.swift | 1 + Sources/_StringProcessing/Regex/DSLTree.swift | 6 ++++ .../_CharacterClassModel.swift | 1 + Tests/RegexBuilderTests/AlgorithmsTests.swift | 1 + 18 files changed, 79 insertions(+), 9 deletions(-) diff --git a/Package.swift b/Package.swift index e95d98b67..01c6adcb1 100644 --- a/Package.swift +++ b/Package.swift @@ -3,6 +3,13 @@ import PackageDescription +let availabilityDefinition = PackageDescription.SwiftSetting.unsafeFlags([ + "-Xfrontend", + "-define-availability", + "-Xfrontend", + #""SwiftStdlib 5.7:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999""# +]) + let package = Package( name: "swift-experimental-string-processing", products: [ @@ -30,12 +37,14 @@ let package = Package( name: "_RegexParser", dependencies: [], swiftSettings: [ - .unsafeFlags(["-enable-library-evolution"]) + .unsafeFlags(["-enable-library-evolution"]), + availabilityDefinition ]), .testTarget( name: "MatchingEngineTests", dependencies: [ - "_RegexParser", "_StringProcessing"]), + "_RegexParser", "_StringProcessing" + ]), .target( name: "_CUnicode", dependencies: []), @@ -44,26 +53,31 @@ let package = Package( dependencies: ["_RegexParser", "_CUnicode"], swiftSettings: [ .unsafeFlags(["-enable-library-evolution"]), + availabilityDefinition ]), .target( name: "RegexBuilder", dependencies: ["_StringProcessing", "_RegexParser"], swiftSettings: [ .unsafeFlags(["-enable-library-evolution"]), - .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]) + .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), + availabilityDefinition ]), .testTarget( name: "RegexTests", - dependencies: ["_StringProcessing"]), + dependencies: ["_StringProcessing"], + swiftSettings: [availabilityDefinition]), .testTarget( name: "RegexBuilderTests", dependencies: ["_StringProcessing", "RegexBuilder"], swiftSettings: [ - .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]) + .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), + availabilityDefinition ]), .target( name: "Prototypes", - dependencies: ["_RegexParser", "_StringProcessing"]), + dependencies: ["_RegexParser", "_StringProcessing"], + swiftSettings: [availabilityDefinition]), // MARK: Scripts .executableTarget( @@ -84,11 +98,12 @@ let package = Package( name: "Exercises", dependencies: ["_RegexParser", "Prototypes", "_StringProcessing", "RegexBuilder"], swiftSettings: [ - .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]) + .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), + availabilityDefinition ]), .testTarget( name: "ExercisesTests", - dependencies: ["Exercises"]), + dependencies: ["Exercises"], + swiftSettings: [availabilityDefinition]), ] ) - diff --git a/Sources/RegexBuilder/Anchor.swift b/Sources/RegexBuilder/Anchor.swift index ba910bd30..7933b987a 100644 --- a/Sources/RegexBuilder/Anchor.swift +++ b/Sources/RegexBuilder/Anchor.swift @@ -12,6 +12,7 @@ import _RegexParser @_spi(RegexBuilder) import _StringProcessing +@available(SwiftStdlib 5.7, *) public struct Anchor { internal enum Kind { case startOfSubject @@ -107,6 +108,7 @@ extension Anchor { } } +@available(SwiftStdlib 5.7, *) public struct Lookahead: _BuiltinRegexComponent { public var regex: Regex diff --git a/Sources/RegexBuilder/Builder.swift b/Sources/RegexBuilder/Builder.swift index 8921c8f25..be9a48e36 100644 --- a/Sources/RegexBuilder/Builder.swift +++ b/Sources/RegexBuilder/Builder.swift @@ -11,6 +11,7 @@ @_spi(RegexBuilder) import _StringProcessing +@available(SwiftStdlib 5.7, *) @resultBuilder public enum RegexComponentBuilder { public static func buildBlock() -> Regex { diff --git a/Sources/RegexBuilder/CharacterClass.swift b/Sources/RegexBuilder/CharacterClass.swift index 78ebd49a2..99e981d33 100644 --- a/Sources/RegexBuilder/CharacterClass.swift +++ b/Sources/RegexBuilder/CharacterClass.swift @@ -12,6 +12,7 @@ import _RegexParser @_spi(RegexBuilder) import _StringProcessing +@available(SwiftStdlib 5.7, *) public struct CharacterClass { internal var ccc: DSLTree.CustomCharacterClass @@ -122,6 +123,7 @@ extension CharacterClass { } /// Range syntax for characters in `CharacterClass`es. +@available(SwiftStdlib 5.7, *) public func ...(lhs: Character, rhs: Character) -> CharacterClass { let range: DSLTree.CustomCharacterClass.Member = .range(.char(lhs), .char(rhs)) let ccc = DSLTree.CustomCharacterClass(members: [range], isInverted: false) @@ -130,6 +132,7 @@ public func ...(lhs: Character, rhs: Character) -> CharacterClass { /// Range syntax for unicode scalars in `CharacterClass`es. @_disfavoredOverload +@available(SwiftStdlib 5.7, *) public func ...(lhs: UnicodeScalar, rhs: UnicodeScalar) -> CharacterClass { let range: DSLTree.CustomCharacterClass.Member = .range(.scalar(lhs), .scalar(rhs)) let ccc = DSLTree.CustomCharacterClass(members: [range], isInverted: false) diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 80662be41..717e172b0 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -54,6 +54,7 @@ extension _BuiltinRegexComponent { // Note: Quantifiers are currently gyb'd. /// Specifies how much to attempt to match when using a quantifier. +@available(SwiftStdlib 5.7, *) public struct QuantificationBehavior { internal enum Kind { case eagerly @@ -121,6 +122,7 @@ extension QuantificationBehavior { } } +@available(SwiftStdlib 5.7, *) public struct OneOrMore: _BuiltinRegexComponent { public var regex: Regex @@ -132,6 +134,7 @@ public struct OneOrMore: _BuiltinRegexComponent { // Variadics.swift. } +@available(SwiftStdlib 5.7, *) public struct ZeroOrMore: _BuiltinRegexComponent { public var regex: Regex @@ -143,6 +146,7 @@ public struct ZeroOrMore: _BuiltinRegexComponent { // Variadics.swift. } +@available(SwiftStdlib 5.7, *) public struct Optionally: _BuiltinRegexComponent { public var regex: Regex @@ -154,6 +158,7 @@ public struct Optionally: _BuiltinRegexComponent { // Variadics.swift. } +@available(SwiftStdlib 5.7, *) public struct Repeat: _BuiltinRegexComponent { public var regex: Regex @@ -179,6 +184,7 @@ public struct Repeat: _BuiltinRegexComponent { // ) -> R where R.Match == (W, C...) // } +@available(SwiftStdlib 5.7, *) @resultBuilder public struct AlternationBuilder { @_disfavoredOverload @@ -201,6 +207,7 @@ public struct AlternationBuilder { } } +@available(SwiftStdlib 5.7, *) public struct ChoiceOf: _BuiltinRegexComponent { public var regex: Regex @@ -215,6 +222,7 @@ public struct ChoiceOf: _BuiltinRegexComponent { // MARK: - Capture +@available(SwiftStdlib 5.7, *) public struct Capture: _BuiltinRegexComponent { public var regex: Regex @@ -225,6 +233,7 @@ public struct Capture: _BuiltinRegexComponent { // Note: Public initializers are currently gyb'd. See Variadics.swift. } +@available(SwiftStdlib 5.7, *) public struct TryCapture: _BuiltinRegexComponent { public var regex: Regex @@ -239,6 +248,7 @@ public struct TryCapture: _BuiltinRegexComponent { /// An atomic group, i.e. opens a local backtracking scope which, upon successful exit, /// discards any remaining backtracking points from within the scope +@available(SwiftStdlib 5.7, *) public struct Local: _BuiltinRegexComponent { public var regex: Regex @@ -249,6 +259,7 @@ public struct Local: _BuiltinRegexComponent { // MARK: - Backreference +@available(SwiftStdlib 5.7, *) public struct Reference: RegexComponent { let id = ReferenceID() diff --git a/Sources/RegexBuilder/Match.swift b/Sources/RegexBuilder/Match.swift index e6718d96b..32dc889d9 100644 --- a/Sources/RegexBuilder/Match.swift +++ b/Sources/RegexBuilder/Match.swift @@ -12,12 +12,14 @@ import _StringProcessing extension String { + @available(SwiftStdlib 5.7, *) public func wholeMatch( @RegexComponentBuilder of content: () -> R ) -> Regex.Match? { wholeMatch(of: content()) } + @available(SwiftStdlib 5.7, *) public func prefixMatch( @RegexComponentBuilder of content: () -> R ) -> Regex.Match? { @@ -26,12 +28,14 @@ extension String { } extension Substring { + @available(SwiftStdlib 5.7, *) public func wholeMatch( @RegexComponentBuilder of content: () -> R ) -> Regex.Match? { wholeMatch(of: content()) } + @available(SwiftStdlib 5.7, *) public func prefixMatch( @RegexComponentBuilder of content: () -> R ) -> Regex.Match? { diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift index 46568192f..2f38095d8 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift @@ -27,6 +27,7 @@ extension Collection where Element: Equatable { /// - Parameter other: A sequence to search for within this collection. /// - Returns: `true` if the collection contains the specified sequence, /// otherwise `false`. + @available(SwiftStdlib 5.7, *) public func contains(_ other: S) -> Bool where S.Element == Element { @@ -50,6 +51,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: A regex to search for within this collection. /// - Returns: `true` if the regex was found in the collection, otherwise /// `false`. + @available(SwiftStdlib 5.7, *) public func contains(_ regex: R) -> Bool { contains(RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift index 405fe47ef..e75cdbdc4 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift @@ -37,6 +37,7 @@ extension Collection where Element: Equatable { /// - Parameter sequence: The sequence to search for. /// - Returns: A range in the collection of the first occurrence of `sequence`. /// Returns nil if `sequence` is not found. + @available(SwiftStdlib 5.7, *) public func firstRange( of sequence: S ) -> Range? where S.Element == Element { @@ -52,6 +53,7 @@ extension BidirectionalCollection where Element: Comparable { /// - Parameter other: The sequence to search for. /// - Returns: A range in the collection of the first occurrence of `sequence`. /// Returns `nil` if `sequence` is not found. + @available(SwiftStdlib 5.7, *) public func firstRange( of other: S ) -> Range? where S.Element == Element { @@ -71,6 +73,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: The regex to search for. /// - Returns: A range in the collection of the first occurrence of `regex`. /// Returns `nil` if `regex` is not found. + @available(SwiftStdlib 5.7, *) public func firstRange(of regex: R) -> Range? { firstRange(of: RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift index bc23a284c..4a6da6c10 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift @@ -77,6 +77,7 @@ extension RangeReplaceableCollection where Element: Equatable { /// to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of `other` in /// `subrange` of the collection are replaced by `replacement`. + @available(SwiftStdlib 5.7, *) public func replacing( _ other: S, with replacement: Replacement, @@ -99,6 +100,7 @@ extension RangeReplaceableCollection where Element: Equatable { /// to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of `other` in /// `subrange` of the collection are replaced by `replacement`. + @available(SwiftStdlib 5.7, *) public func replacing( _ other: S, with replacement: Replacement, @@ -117,6 +119,7 @@ extension RangeReplaceableCollection where Element: Equatable { /// - replacement: The new elements to add to the collection. /// - maxReplacements: A number specifying how many occurrences of `other` /// to replace. Default is `Int.max`. + @available(SwiftStdlib 5.7, *) public mutating func replace( _ other: S, with replacement: Replacement, @@ -184,6 +187,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// sequence matching `regex` to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` in `subrange` are replaced by `replacement`. + @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, with replacement: Replacement, @@ -206,6 +210,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// sequence matching `regex` to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. + @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, with replacement: Replacement, @@ -225,6 +230,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - replacement: The new elements to add to the collection. /// - maxReplacements: A number specifying how many occurrences of the /// sequence matching `regex` to replace. Default is `Int.max`. + @available(SwiftStdlib 5.7, *) public mutating func replace( _ regex: R, with replacement: Replacement, diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift index 346094f9e..01572fe49 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift @@ -53,6 +53,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: A regex to compare to this sequence. /// - Returns: `true` if the initial elements of the sequence matches the /// beginning of `regex`; otherwise, `false`. + @available(SwiftStdlib 5.7, *) public func starts(with regex: R) -> Bool { starts(with: RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift index ed7cd7bc4..fd0dbefdb 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift @@ -111,6 +111,7 @@ extension Collection { } extension Collection where SubSequence == Self { + @available(SwiftStdlib 5.7, *) public mutating func trimPrefix( while predicate: @escaping (Element) -> Bool ) { @@ -121,6 +122,7 @@ extension Collection where SubSequence == Self { extension RangeReplaceableCollection { @_disfavoredOverload + @available(SwiftStdlib 5.7, *) public mutating func trimPrefix( while predicate: @escaping (Element) -> Bool ) { @@ -185,6 +187,7 @@ extension Collection where Element: Equatable { /// element should be removed from the collection. /// - Returns: A collection containing the elements of the collection that are /// not removed by `predicate`. + @available(SwiftStdlib 5.7, *) public func trimmingPrefix( _ prefix: Prefix ) -> SubSequence where Prefix.Element == Element { @@ -198,6 +201,7 @@ extension Collection where SubSequence == Self, Element: Equatable { /// - Parameter predicate: A closure that takes an element of the sequence /// as its argument and returns a Boolean value indicating whether the /// element should be removed from the collection. + @available(SwiftStdlib 5.7, *) public mutating func trimPrefix( _ prefix: Prefix ) where Prefix.Element == Element { @@ -212,6 +216,7 @@ extension RangeReplaceableCollection where Element: Equatable { /// - Parameter predicate: A closure that takes an element of the sequence /// as its argument and returns a Boolean value indicating whether the /// element should be removed from the collection. + @available(SwiftStdlib 5.7, *) public mutating func trimPrefix( _ prefix: Prefix ) where Prefix.Element == Element { @@ -279,6 +284,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter prefix: The collection to remove from this collection. /// - Returns: A collection containing the elements that does not match /// `prefix` from the start. + @available(SwiftStdlib 5.7, *) public func trimmingPrefix(_ regex: R) -> SubSequence { trimmingPrefix(RegexConsumer(regex)) } @@ -297,6 +303,7 @@ extension RangeReplaceableCollection { /// Removes the initial elements that matches the given regex. /// - Parameter regex: The regex to remove from this collection. + @available(SwiftStdlib 5.7, *) public mutating func trimPrefix(_ regex: R) { trimPrefix(RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift index 74ab48839..82ca00797 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift @@ -122,6 +122,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// sequence matching `regex` to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. + @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, with replacement: (Regex.Match) throws -> Replacement, @@ -157,6 +158,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// sequence matching `regex` to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. + @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, with replacement: (Regex.Match) throws -> Replacement, @@ -177,6 +179,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// including captures, and returns a replacement collection. /// - maxReplacements: A number specifying how many occurrences of the /// sequence matching `regex` to replace. Default is `Int.max`. + @available(SwiftStdlib 5.7, *) public mutating func replace( _ regex: R, with replacement: (Regex.Match) throws -> Replacement, diff --git a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift index bd0fc47c9..ea9659faf 100644 --- a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift +++ b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift @@ -38,6 +38,7 @@ extension Regex.Match where Output == AnyRegexOutput { } /// A type-erased regex output +@available(SwiftStdlib 5.7, *) public struct AnyRegexOutput { let input: String fileprivate let _elements: [ElementRepresentation] diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index 96d0f3a68..b77ee7ece 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -13,6 +13,7 @@ import _RegexParser /// A type that represents a regular expression. +@available(SwiftStdlib 5.7, *) public protocol RegexComponent { associatedtype Output var regex: Regex { get } @@ -25,6 +26,7 @@ public protocol RegexComponent { /// print(match.0) // "axb" /// print(match.1) // "x" /// +@available(SwiftStdlib 5.7, *) public struct Regex: RegexComponent { let program: Program diff --git a/Sources/_StringProcessing/Regex/DSLConsumers.swift b/Sources/_StringProcessing/Regex/DSLConsumers.swift index 8d64f8355..8bca244c2 100644 --- a/Sources/_StringProcessing/Regex/DSLConsumers.swift +++ b/Sources/_StringProcessing/Regex/DSLConsumers.swift @@ -9,6 +9,7 @@ // //===----------------------------------------------------------------------===// +@available(SwiftStdlib 5.7, *) public protocol CustomRegexComponent: RegexComponent { func match( _ input: String, diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index f37505cb4..6ae4804e5 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -12,6 +12,7 @@ import _RegexParser @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public struct DSLTree { var root: Node var options: Options? @@ -162,6 +163,7 @@ extension DSLTree { // CollectionConsumer @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public typealias _ConsumerInterface = ( String, Range ) throws -> String.Index? @@ -169,12 +171,14 @@ public typealias _ConsumerInterface = ( // Type producing consume // TODO: better name @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public typealias _MatcherInterface = ( String, String.Index, Range ) throws -> (String.Index, Any)? // Character-set (post grapheme segmentation) @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public typealias _CharacterPredicateInterface = ( (Character) -> Bool ) @@ -375,6 +379,7 @@ extension DSLTree.Node { } @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public struct ReferenceID: Hashable, Equatable { private static var counter: Int = 0 var base: Int @@ -386,6 +391,7 @@ public struct ReferenceID: Hashable, Equatable { } @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public struct CaptureTransform: Hashable, CustomStringConvertible { public enum Closure { case failable((Substring) throws -> Any?) diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index e184689f1..0c45d2b6c 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -16,6 +16,7 @@ import _RegexParser // of parsing or to store in an AST @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public struct _CharacterClassModel: Hashable { /// The actual character class to match. var cc: Representation diff --git a/Tests/RegexBuilderTests/AlgorithmsTests.swift b/Tests/RegexBuilderTests/AlgorithmsTests.swift index 7625af385..fed584ff7 100644 --- a/Tests/RegexBuilderTests/AlgorithmsTests.swift +++ b/Tests/RegexBuilderTests/AlgorithmsTests.swift @@ -13,6 +13,7 @@ import XCTest import _StringProcessing @testable import RegexBuilder +@available(SwiftStdlib 5.7, *) class RegexConsumerTests: XCTestCase { // FIXME: enable this test when we update the return type of `matches(of:)` // when SE-0346 is available From 6f7ab9650c156b7aad8838f2bff6e71e5af50342 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 14 Apr 2022 20:04:50 +0100 Subject: [PATCH 065/133] Throw error if we encounter stray opening '(' This should be unreachable, let's make sure of that. Doing so requires generalizing the handling of LocatedError a bit. --- .../Regex/Parse/LexicalAnalysis.swift | 21 +++++++++++++------ .../Regex/Parse/SourceLocation.swift | 5 +++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift index f70989c9f..daa629055 100644 --- a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift +++ b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift @@ -21,6 +21,16 @@ API convention: - eat() and tryEat() is still used by the parser as a character-by-character interface */ +extension Error { + func addingLocation(_ loc: Range) -> Error { + // If we're already a LocatedError, don't change the location. + if self is _LocatedErrorProtocol { + return self + } + return Source.LocatedError(self, loc) + } +} + extension Source { // MARK: - recordLoc @@ -51,12 +61,8 @@ extension Source { do { guard let result = try f(&self) else { return nil } return Located(result, start.. { - throw e - } catch let e as ParseError { - throw LocatedError(e, start..: Error { + public struct LocatedError: Error, _LocatedErrorProtocol { public let error: E public let location: SourceLocation @@ -70,7 +72,6 @@ extension Source { self.error = v self.location = Location(r) } - } /// Located value: a value wrapped with a source range From aede1f79ab228c80f24103bffcbd3beb303bdac6 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 14 Apr 2022 20:04:51 +0100 Subject: [PATCH 066/133] Change matching option scoping behavior to match PCRE Previously we would always parse a "change matching option" sequence as a group, and for the isolated syntax e.g `(?x)`, we would have it implicitly wrap everything after in the same group by having it do a recursive parse. This matched the Oniguruma behavior for such isolated groups, and was easy to implement, but its behavior is quite unintuitive when it comes to alternations, as e.g `a(?x)b|c` becomes `a(?x:b|c)`, which may not be expected. Instead, let's follow PCRE's behavior by having such isolated cases affect the syntax options for the remainder of the current group, including across alternation branches. This is done by lexing such cases as atoms (as they aren't really group-like anymore), and having them change the syntax options when we encounter them. The existing scoping rules around groups take care of resetting the options when we exit the scope. --- Sources/_RegexParser/Regex/AST/Atom.swift | 10 +- Sources/_RegexParser/Regex/AST/Group.swift | 19 +- .../Regex/Parse/LexicalAnalysis.swift | 98 ++-- Sources/_RegexParser/Regex/Parse/Parse.swift | 64 ++- .../_RegexParser/Regex/Printing/DumpAST.swift | 34 +- Sources/_StringProcessing/ByteCodeGen.swift | 8 +- .../_StringProcessing/ConsumerInterface.swift | 7 +- .../_StringProcessing/PrintAsPattern.swift | 5 + .../Regex/ASTConversion.swift | 9 +- Sources/_StringProcessing/Regex/DSLTree.swift | 2 + Sources/_StringProcessing/Regex/Options.swift | 3 +- .../Utility/ASTBuilder.swift | 9 +- Tests/RegexTests/MatchTests.swift | 11 + Tests/RegexTests/ParseTests.swift | 471 +++++++++--------- 14 files changed, 404 insertions(+), 346 deletions(-) diff --git a/Sources/_RegexParser/Regex/AST/Atom.swift b/Sources/_RegexParser/Regex/AST/Atom.swift index 6482c4042..9cc2e9a96 100644 --- a/Sources/_RegexParser/Regex/AST/Atom.swift +++ b/Sources/_RegexParser/Regex/AST/Atom.swift @@ -72,6 +72,9 @@ extension AST { // (*ACCEPT), (*FAIL), ... case backtrackingDirective(BacktrackingDirective) + + // (?i), (?i-m), ... + case changeMatchingOptions(MatchingOptionSequence) } } } @@ -91,6 +94,7 @@ extension AST.Atom { case .subpattern(let v): return v case .callout(let v): return v case .backtrackingDirective(let v): return v + case .changeMatchingOptions(let v): return v case .any: return nil case .startOfLine: return nil case .endOfLine: return nil @@ -691,7 +695,7 @@ extension AST.Atom { return nil case .property, .any, .startOfLine, .endOfLine, .backreference, .subpattern, - .callout, .backtrackingDirective: + .callout, .backtrackingDirective, .changeMatchingOptions: return nil } } @@ -731,7 +735,7 @@ extension AST.Atom { case .property, .escaped, .any, .startOfLine, .endOfLine, .backreference, .subpattern, .namedCharacter, .callout, - .backtrackingDirective: + .backtrackingDirective, .changeMatchingOptions: return nil } } @@ -740,6 +744,8 @@ extension AST.Atom { switch kind { case .backtrackingDirective(let b): return b.isQuantifiable + case .changeMatchingOptions: + return false // TODO: Are callouts quantifiable? default: return true diff --git a/Sources/_RegexParser/Regex/AST/Group.swift b/Sources/_RegexParser/Regex/AST/Group.swift index 81e0931ad..a8c4f8b0f 100644 --- a/Sources/_RegexParser/Regex/AST/Group.swift +++ b/Sources/_RegexParser/Regex/AST/Group.swift @@ -68,9 +68,7 @@ extension AST { case atomicScriptRun // (?iJmnsUxxxDPSWy{..}-iJmnsUxxxDPSW:) - // Isolated options are written as e.g (?i), and implicitly form a group - // containing all the following elements of the current group. - case changeMatchingOptions(MatchingOptionSequence, isIsolated: Bool) + case changeMatchingOptions(MatchingOptionSequence) // NOTE: Comments appear to be groups, but are not parsed // the same. They parse more like quotes, so are not @@ -87,21 +85,6 @@ extension AST.Group.Kind { } } - /// Whether this is a group with an implicit scope, e.g isolated matching - /// options implicitly become parent groups for the rest of the elements in - /// the current group: - /// - /// (a(?i)bc)de -> (a(?i:bc))de - /// - public var hasImplicitScope: Bool { - switch self { - case .changeMatchingOptions(_, let isIsolated): - return isIsolated - default: - return false - } - } - /// If this is a named group, its name, `nil` otherwise. public var name: String? { switch self { diff --git a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift index daa629055..e8b7e9e18 100644 --- a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift +++ b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift @@ -712,6 +712,22 @@ extension Source { return .init(caretLoc: nil, adding: adding, minusLoc: nil, removing: []) } + /// A matching option changing atom. + /// + /// '(?' MatchingOptionSeq ')' + /// + mutating func lexChangeMatchingOptionAtom( + context: ParsingContext + ) throws -> AST.MatchingOptionSequence? { + try tryEating { src in + guard src.tryEat(sequence: "(?"), + let seq = try src.lexMatchingOptionSequence(context: context) + else { return nil } + try src.expect(")") + return seq + } + } + /// Try to consume explicitly spelled-out PCRE2 group syntax. mutating func lexExplicitPCRE2GroupStart() -> AST.Group.Kind? { tryEating { src in @@ -852,7 +868,7 @@ extension Source { // otherwise a matching option specifier. Conversely, '(?P' can be the // start of a matching option sequence, or a reference if it is followed // by '=' or '<'. - guard !src.shouldLexGroupLikeAtom() else { return nil } + guard !src.shouldLexGroupLikeAtom(context: context) else { return nil } guard src.tryEat("(") else { return nil } if src.tryEat("?") { @@ -877,22 +893,13 @@ extension Source { // Matching option changing group (?iJmnsUxxxDPSWy{..}-iJmnsUxxxDPSW:). if let seq = try src.lexMatchingOptionSequence(context: context) { - if src.tryEat(":") { - return .changeMatchingOptions(seq, isIsolated: false) - } - // If this isn't start of an explicit group, we should have an - // implicit group that covers the remaining elements of the current - // group. - // TODO: This implicit scoping behavior matches Oniguruma, but PCRE - // also does it across alternations, which will require additional - // handling. - guard src.tryEat(")") else { + guard src.tryEat(":") else { if let next = src.peek() { throw ParseError.invalidMatchingOption(next) } throw ParseError.expected(")") } - return .changeMatchingOptions(seq, isIsolated: true) + return .changeMatchingOptions(seq) } guard let next = src.peek() else { @@ -1041,18 +1048,8 @@ extension Source { context: ParsingContext ) throws -> Located? { try tryEating { src in - guard src.tryEat(sequence: "(?"), - let group = try src.lexGroupStart(context: context) - else { return nil } - - // Implicitly scoped groups are not supported here. - guard !group.value.hasImplicitScope else { - throw LocatedError( - ParseError.unsupportedCondition("implicitly scoped group"), - group.location - ) - } - return group + guard src.tryEat(sequence: "(?") else { return nil } + return try src.lexGroupStart(context: context) } } @@ -1239,17 +1236,19 @@ extension Source { allowWholePatternRef: Bool = false, allowRecursionLevel: Bool = false ) throws -> AST.Reference? { let kind = try recordLoc { src -> AST.Reference.Kind? in - // Note this logic should match canLexNumberedReference. - if src.tryEat("+") { - return .relative(try src.expectNumber().value) - } - if src.tryEat("-") { - return .relative(try -src.expectNumber().value) - } - if let num = try src.lexNumber() { - return .absolute(num.value) + try src.tryEating { src in + // Note this logic should match canLexNumberedReference. + if src.tryEat("+"), let num = try src.lexNumber() { + return .relative(num.value) + } + if src.tryEat("-"), let num = try src.lexNumber() { + return .relative(-num.value) + } + if let num = try src.lexNumber() { + return .absolute(num.value) + } + return nil } - return nil } guard let kind = kind else { return nil } guard allowWholePatternRef || kind.value != .recurseWholePattern else { @@ -1478,8 +1477,21 @@ extension Source { return src.canLexNumberedReference() } + private func canLexMatchingOptionsAsAtom(context: ParsingContext) -> Bool { + var src = self + + // See if we can lex a matching option sequence that terminates in ')'. Such + // a sequence is an atom. If an error is thrown, there are invalid elements + // of the matching option sequence. In such a case, we can lex as a group + // and diagnose the invalid group kind. + guard (try? src.lexMatchingOptionSequence(context: context)) != nil else { + return false + } + return src.tryEat(")") + } + /// Whether a group specifier should be lexed as an atom instead of a group. - private func shouldLexGroupLikeAtom() -> Bool { + private func shouldLexGroupLikeAtom(context: ParsingContext) -> Bool { var src = self guard src.tryEat("(") else { return false } @@ -1493,6 +1505,9 @@ extension Source { // The start of an Oniguruma 'of-contents' callout. if src.tryEat("{") { return true } + // A matching option atom (?x), (?i), ... + if src.canLexMatchingOptionsAsAtom(context: context) { return true } + return false } // The start of a backreference directive or Oniguruma named callout. @@ -1753,13 +1768,20 @@ extension Source { /// /// GroupLikeAtom -> GroupLikeReference | Callout | BacktrackingDirective /// - mutating func expectGroupLikeAtom() throws -> AST.Atom.Kind { + mutating func expectGroupLikeAtom( + context: ParsingContext + ) throws -> AST.Atom.Kind { try recordLoc { src in // References that look like groups, e.g (?R), (?1), ... if let ref = try src.lexGroupLikeReference() { return ref.value } + // Change matching options atom (?i), (?x-i), ... + if let seq = try src.lexChangeMatchingOptionAtom(context: context) { + return .changeMatchingOptions(seq) + } + // (*ACCEPT), (*FAIL), (*MARK), ... if let b = try src.lexBacktrackingDirective() { return .backtrackingDirective(b) @@ -1828,8 +1850,8 @@ extension Source { // If we have group syntax that was skipped over in lexGroupStart, we // need to handle it as an atom, or throw an error. - if !customCC && src.shouldLexGroupLikeAtom() { - return try src.expectGroupLikeAtom() + if !customCC && src.shouldLexGroupLikeAtom(context: context) { + return try src.expectGroupLikeAtom(context: context) } // A quantifier here is invalid. diff --git a/Sources/_RegexParser/Regex/Parse/Parse.swift b/Sources/_RegexParser/Regex/Parse/Parse.swift index b24097b83..975012546 100644 --- a/Sources/_RegexParser/Regex/Parse/Parse.swift +++ b/Sources/_RegexParser/Regex/Parse/Parse.swift @@ -282,42 +282,53 @@ extension Parser { loc(start))) } + /// Apply the syntax options of a given matching option sequence to the + /// current set of options. + private mutating func applySyntaxOptions( + of opts: AST.MatchingOptionSequence + ) { + // We skip this for multi-line, as extended syntax is always enabled there. + if context.syntax.contains(.multilineExtendedSyntax) { return } + + // Check if we're introducing or removing extended syntax. + // TODO: PCRE differentiates between (?x) and (?xx) where only the latter + // handles non-semantic whitespace in a custom character class. Other + // engines such as Oniguruma, Java, and ICU do this under (?x). Therefore, + // treat (?x) and (?xx) as the same option here. If we ever get a strict + // PCRE mode, we will need to change this to handle that. + if opts.resetsCurrentOptions { + context.syntax.remove(.extendedSyntax) + } + if opts.adding.contains(where: \.isAnyExtended) { + context.syntax.insert(.extendedSyntax) + } + if opts.removing.contains(where: \.isAnyExtended) { + context.syntax.remove(.extendedSyntax) + } + } + + /// Apply the syntax options of a matching option changing group to the + /// current set of options. + private mutating func applySyntaxOptions(of group: AST.Group.Kind) { + if case .changeMatchingOptions(let seq) = group { + applySyntaxOptions(of: seq) + } + } + /// Perform a recursive parse for the body of a group. mutating func parseGroupBody( start: Source.Position, _ kind: AST.Located ) throws -> AST.Group { context.recordGroup(kind.value) - // Check if we're introducing or removing extended syntax. We skip this for - // multi-line, as extended syntax is always enabled there. - // TODO: PCRE differentiates between (?x) and (?xx) where only the latter - // handles non-semantic whitespace in a custom character class. Other - // engines such as Oniguruma, Java, and ICU do this under (?x). Therefore, - // treat (?x) and (?xx) as the same option here. If we ever get a strict - // PCRE mode, we will need to change this to handle that. let currentSyntax = context.syntax - if !context.syntax.contains(.multilineExtendedSyntax) { - if case .changeMatchingOptions(let c, isIsolated: _) = kind.value { - if c.resetsCurrentOptions { - context.syntax.remove(.extendedSyntax) - } - if c.adding.contains(where: \.isAnyExtended) { - context.syntax.insert(.extendedSyntax) - } - if c.removing.contains(where: \.isAnyExtended) { - context.syntax.remove(.extendedSyntax) - } - } - } + applySyntaxOptions(of: kind.value) defer { context.syntax = currentSyntax } let child = try parseNode() - // An implicit scoped group has already consumed its closing paren. - if !kind.value.hasImplicitScope { - try source.expect(")") - } + try source.expect(")") return .init(kind, child, loc(start)) } @@ -409,6 +420,11 @@ extension Parser { } if let atom = try source.lexAtom(context: context) { + // If we have a change matching options atom, apply the syntax options. We + // already take care of scoping syntax options within a group. + if case .changeMatchingOptions(let opts) = atom.kind { + applySyntaxOptions(of: opts) + } // TODO: track source locations return .atom(atom) } diff --git a/Sources/_RegexParser/Regex/Printing/DumpAST.swift b/Sources/_RegexParser/Regex/Printing/DumpAST.swift index 986f3d86e..8565b14e9 100644 --- a/Sources/_RegexParser/Regex/Printing/DumpAST.swift +++ b/Sources/_RegexParser/Regex/Printing/DumpAST.swift @@ -156,6 +156,9 @@ extension AST.Atom { case .backtrackingDirective(let d): return "\(d)" + case .changeMatchingOptions(let opts): + return "changeMatchingOptions<\(opts)>" + case .char, .scalar: fatalError("Unreachable") } @@ -225,22 +228,21 @@ extension AST.Reference: _ASTPrintable { extension AST.Group.Kind: _ASTPrintable { public var _dumpBase: String { switch self { - case .capture: return "capture" - case .namedCapture(let s): return "capture<\(s.value)>" - case .balancedCapture(let b): return "balanced capture \(b)" - case .nonCapture: return "nonCapture" - case .nonCaptureReset: return "nonCaptureReset" - case .atomicNonCapturing: return "atomicNonCapturing" - case .lookahead: return "lookahead" - case .negativeLookahead: return "negativeLookahead" - case .nonAtomicLookahead: return "nonAtomicLookahead" - case .lookbehind: return "lookbehind" - case .negativeLookbehind: return "negativeLookbehind" - case .nonAtomicLookbehind: return "nonAtomicLookbehind" - case .scriptRun: return "scriptRun" - case .atomicScriptRun: return "atomicScriptRun" - case .changeMatchingOptions(let seq, let isIsolated): - return "changeMatchingOptions<\(seq), \(isIsolated)>" + case .capture: return "capture" + case .namedCapture(let s): return "capture<\(s.value)>" + case .balancedCapture(let b): return "balanced capture \(b)" + case .nonCapture: return "nonCapture" + case .nonCaptureReset: return "nonCaptureReset" + case .atomicNonCapturing: return "atomicNonCapturing" + case .lookahead: return "lookahead" + case .negativeLookahead: return "negativeLookahead" + case .nonAtomicLookahead: return "nonAtomicLookahead" + case .lookbehind: return "lookbehind" + case .negativeLookbehind: return "negativeLookbehind" + case .nonAtomicLookbehind: return "nonAtomicLookbehind" + case .scriptRun: return "scriptRun" + case .atomicScriptRun: return "atomicScriptRun" + case .changeMatchingOptions(let seq): return "changeMatchingOptions<\(seq)>" } } } diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index 70233cf4f..c44b5af94 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -34,6 +34,9 @@ extension Compiler.ByteCodeGen { case let .symbolicReference(id): builder.buildUnresolvedReference(id: id) + case let .changeMatchingOptions(optionSequence): + options.apply(optionSequence) + case let .unconverted(astAtom): if let consumer = try astAtom.generateConsumer(options) { builder.buildConsume(by: consumer) @@ -347,7 +350,7 @@ extension Compiler.ByteCodeGen { case .capture, .namedCapture, .balancedCapture: throw Unreachable("These should produce a capture node") - case .changeMatchingOptions(let optionSequence, _): + case .changeMatchingOptions(let optionSequence): options.apply(optionSequence) try emitNode(child) @@ -573,6 +576,9 @@ extension Compiler.ByteCodeGen { } case let .capture(_, refId, child): + options.beginScope() + defer { options.endScope() } + let cap = builder.makeCapture(id: refId) switch child { case let .matcher(_, m): diff --git a/Sources/_StringProcessing/ConsumerInterface.swift b/Sources/_StringProcessing/ConsumerInterface.swift index 49e459c0b..b49804ca1 100644 --- a/Sources/_StringProcessing/ConsumerInterface.swift +++ b/Sources/_StringProcessing/ConsumerInterface.swift @@ -100,6 +100,10 @@ extension DSLTree.Atom { // TODO: Should we handle? return nil + case .changeMatchingOptions: + // TODO: Should we handle? + return nil + case let .unconverted(a): return try a.generateConsumer(opts) } @@ -178,7 +182,8 @@ extension AST.Atom { return nil case .escaped, .keyboardControl, .keyboardMeta, .keyboardMetaControl, - .backreference, .subpattern, .callout, .backtrackingDirective: + .backreference, .subpattern, .callout, .backtrackingDirective, + .changeMatchingOptions: // FIXME: implement return nil } diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index 1998aa75b..8e1dd8322 100644 --- a/Sources/_StringProcessing/PrintAsPattern.swift +++ b/Sources/_StringProcessing/PrintAsPattern.swift @@ -136,6 +136,8 @@ extension PrettyPrinter { print("/* TOOD: backreferences */") case .symbolicReference: print("/* TOOD: symbolic references */") + case .changeMatchingOptions: + print("/* TODO: change matching options */") } case .trivia: @@ -319,6 +321,9 @@ extension AST.Atom { case .backtrackingDirective: return " /* TODO: backtracking directive */" + + case .changeMatchingOptions: + return "/* TODO: change matching options */" } } } diff --git a/Sources/_StringProcessing/Regex/ASTConversion.swift b/Sources/_StringProcessing/Regex/ASTConversion.swift index f773bd275..ac88dcd73 100644 --- a/Sources/_StringProcessing/Regex/ASTConversion.swift +++ b/Sources/_StringProcessing/Regex/ASTConversion.swift @@ -206,10 +206,11 @@ extension AST.Atom { } switch self.kind { - case let .char(c): return .char(c) - case let .scalar(s): return .scalar(s) - case .any: return .any - case let .backreference(r): return .backreference(r) + case let .char(c): return .char(c) + case let .scalar(s): return .scalar(s) + case .any: return .any + case let .backreference(r): return .backreference(r) + case let .changeMatchingOptions(seq): return .changeMatchingOptions(seq) case .escaped(let c) where c.scalarValue != nil: return .scalar(c.scalarValue!) diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index f37505cb4..189b3a22d 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -156,6 +156,8 @@ extension DSLTree { case backreference(AST.Reference) case symbolicReference(ReferenceID) + case changeMatchingOptions(AST.MatchingOptionSequence) + case unconverted(AST.Atom) } } diff --git a/Sources/_StringProcessing/Regex/Options.swift b/Sources/_StringProcessing/Regex/Options.swift index 38fba02d6..32e73b08c 100644 --- a/Sources/_StringProcessing/Regex/Options.swift +++ b/Sources/_StringProcessing/Regex/Options.swift @@ -168,7 +168,6 @@ extension RegexComponent { ? AST.MatchingOptionSequence(adding: [.init(option, location: .fake)]) : AST.MatchingOptionSequence(removing: [.init(option, location: .fake)]) return Regex(node: .nonCapturingGroup( - .changeMatchingOptions(sequence, isIsolated: false), - regex.root)) + .changeMatchingOptions(sequence), regex.root)) } } diff --git a/Sources/_StringProcessing/Utility/ASTBuilder.swift b/Sources/_StringProcessing/Utility/ASTBuilder.swift index 107a3e3c9..c14454a5c 100644 --- a/Sources/_StringProcessing/Utility/ASTBuilder.swift +++ b/Sources/_StringProcessing/Utility/ASTBuilder.swift @@ -119,9 +119,14 @@ func atomicScriptRun(_ child: AST.Node) -> AST.Node { group(.atomicScriptRun, child) } func changeMatchingOptions( - _ seq: AST.MatchingOptionSequence, isIsolated: Bool, _ child: AST.Node + _ seq: AST.MatchingOptionSequence, _ child: AST.Node ) -> AST.Node { - group(.changeMatchingOptions(seq, isIsolated: isIsolated), child) + group(.changeMatchingOptions(seq), child) +} +func changeMatchingOptions( + _ seq: AST.MatchingOptionSequence +) -> AST.Node { + atom(.changeMatchingOptions(seq)) } func matchingOptions( diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index 448ff3211..8e92c5936 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -1319,6 +1319,17 @@ extension RegexTests { firstMatchTest(#"(((?s)a)).b"#, input: "a\nb", match: nil) firstMatchTest(#"(?s)(((?-s)a)).b"#, input: "a\nb", match: "a\nb") firstMatchTest(#"(?s)((?-s)((?i)a)).b"#, input: "a\nb", match: "a\nb") + + // Matching option changing persists across alternations. + firstMatchTest(#"a(?s)b|c|.d"#, input: "abc", match: "ab") + firstMatchTest(#"a(?s)b|c|.d"#, input: "c", match: "c") + firstMatchTest(#"a(?s)b|c|.d"#, input: "a\nd", match: "\nd") + firstMatchTest(#"a(?s)(?^)b|c|.d"#, input: "a\nd", match: nil) + firstMatchTest(#"a(?s)b|.c(?-s)|.d"#, input: "a\nd", match: nil) + firstMatchTest(#"a(?s)b|.c(?-s)|.d"#, input: "a\nc", match: "\nc") + firstMatchTest(#"a(?s)b|c(?-s)|(?^s).d"#, input: "a\nd", match: "\nd") + firstMatchTest(#"a(?:(?s).b)|.c|.d"#, input: "a\nb", match: "a\nb") + firstMatchTest(#"a(?:(?s).b)|.c"#, input: "a\nc", match: nil) } func testOptionMethods() throws { diff --git a/Tests/RegexTests/ParseTests.swift b/Tests/RegexTests/ParseTests.swift index 65dd6ed09..bdae250ba 100644 --- a/Tests/RegexTests/ParseTests.swift +++ b/Tests/RegexTests/ParseTests.swift @@ -464,21 +464,18 @@ extension RegexTests { // classes containing literal ']'. parseTest("[]]", charClass("]")) parseTest("[]a]", charClass("]", "a")) - parseTest( - "(?x)[ ]]", changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - charClass("]")) - ) - parseTest( - "(?x)[ ] ]", changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - charClass("]")) - ) - parseTest( - "(?x)[ ] a ]", changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - charClass("]", "a")) - ) + parseTest("(?x)[ ]]", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + charClass("]") + )) + parseTest("(?x)[ ] ]", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + charClass("]") + )) + parseTest("(?x)[ ] a ]", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + charClass("]", "a") + )) // These are metacharacters in certain contexts, but normal characters // otherwise. @@ -630,14 +627,13 @@ extension RegexTests { "~~*", concat("~", zeroOrMore(of: "~"))) parseTest( - "[ && ]", charClass( - .setOperation([" "], .init(faking: .intersection), [" ", " "])) + "[ && ]", + charClass(.setOperation([" "], .init(faking: .intersection), [" ", " "])) ) - parseTest( - "(?x)[ a && b ]", changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, charClass( - .setOperation(["a"], .init(faking: .intersection), ["b"])) - )) + parseTest("(?x)[ a && b ]", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + charClass(.setOperation(["a"], .init(faking: .intersection), ["b"])) + )) // MARK: Quotes @@ -832,81 +828,67 @@ extension RegexTests { // Matching option changing groups. parseTest("(?-)", changeMatchingOptions( - matchingOptions(), isIsolated: true, empty()) - ) + matchingOptions() + )) parseTest("(?i)", changeMatchingOptions( - matchingOptions(adding: .caseInsensitive), - isIsolated: true, empty()) - ) + matchingOptions(adding: .caseInsensitive) + )) parseTest("(?m)", changeMatchingOptions( - matchingOptions(adding: .multiline), - isIsolated: true, empty()) - ) + matchingOptions(adding: .multiline) + )) parseTest("(?x)", changeMatchingOptions( - matchingOptions(adding: .extended), - isIsolated: true, empty()) - ) + matchingOptions(adding: .extended) + )) parseTest("(?xx)", changeMatchingOptions( - matchingOptions(adding: .extraExtended), - isIsolated: true, empty()) - ) + matchingOptions(adding: .extraExtended) + )) parseTest("(?xxx)", changeMatchingOptions( - matchingOptions(adding: .extraExtended, .extended), - isIsolated: true, empty()) - ) + matchingOptions(adding: .extraExtended, .extended) + )) parseTest("(?P)", changeMatchingOptions( - matchingOptions(adding: .asciiOnlyPOSIXProps), isIsolated: true, empty()) - ) + matchingOptions(adding: .asciiOnlyPOSIXProps) + )) parseTest("(?-i)", changeMatchingOptions( - matchingOptions(removing: .caseInsensitive), - isIsolated: true, empty()) - ) + matchingOptions(removing: .caseInsensitive) + )) parseTest("(?i-s)", changeMatchingOptions( - matchingOptions(adding: .caseInsensitive, removing: .singleLine), - isIsolated: true, empty()) - ) + matchingOptions(adding: .caseInsensitive, removing: .singleLine) + )) parseTest("(?i-is)", changeMatchingOptions( matchingOptions(adding: .caseInsensitive, - removing: .caseInsensitive, .singleLine), - isIsolated: true, empty()) - ) + removing: .caseInsensitive, .singleLine) + )) parseTest("(?:)", nonCapture(empty())) parseTest("(?-:)", changeMatchingOptions( - matchingOptions(), isIsolated: false, empty()) - ) + matchingOptions(), empty() + )) parseTest("(?i:)", changeMatchingOptions( - matchingOptions(adding: .caseInsensitive), - isIsolated: false, empty()) - ) + matchingOptions(adding: .caseInsensitive), empty() + )) parseTest("(?-i:)", changeMatchingOptions( - matchingOptions(removing: .caseInsensitive), - isIsolated: false, empty()) - ) + matchingOptions(removing: .caseInsensitive), empty() + )) parseTest("(?P:)", changeMatchingOptions( - matchingOptions(adding: .asciiOnlyPOSIXProps), isIsolated: false, empty()) - ) + matchingOptions(adding: .asciiOnlyPOSIXProps), empty() + )) parseTest("(?^)", changeMatchingOptions( - unsetMatchingOptions(), - isIsolated: true, empty()) - ) + unsetMatchingOptions() + )) parseTest("(?^:)", changeMatchingOptions( - unsetMatchingOptions(), - isIsolated: false, empty()) - ) + unsetMatchingOptions(), empty() + )) parseTest("(?^ims:)", changeMatchingOptions( unsetMatchingOptions(adding: .caseInsensitive, .multiline, .singleLine), - isIsolated: false, empty()) - ) + empty() + )) parseTest("(?^J:)", changeMatchingOptions( - unsetMatchingOptions(adding: .allowDuplicateGroupNames), - isIsolated: false, empty()) - ) + unsetMatchingOptions(adding: .allowDuplicateGroupNames), empty() + )) parseTest("(?^y{w}:)", changeMatchingOptions( - unsetMatchingOptions(adding: .textSegmentWordMode), - isIsolated: false, empty()) - ) + unsetMatchingOptions(adding: .textSegmentWordMode), empty() + )) let allOptions: [AST.MatchingOption.Kind] = [ .caseInsensitive, .allowDuplicateGroupNames, .multiline, .noAutoCapture, @@ -917,50 +899,64 @@ extension RegexTests { .byteSemantics ] parseTest("(?iJmnsUxxxwDPSWy{g}y{w}Xub-iJmnsUxxxwDPSW)", changeMatchingOptions( - matchingOptions( - adding: allOptions, - removing: allOptions.dropLast(5) - ), - isIsolated: true, empty()) - ) + matchingOptions(adding: allOptions, removing: allOptions.dropLast(5)) + )) parseTest("(?iJmnsUxxxwDPSWy{g}y{w}Xub-iJmnsUxxxwDPSW:)", changeMatchingOptions( - matchingOptions( - adding: allOptions, - removing: allOptions.dropLast(5) - ), - isIsolated: false, empty()) - ) + matchingOptions(adding: allOptions, removing: allOptions.dropLast(5)), empty() + )) parseTest( - "a(b(?i)c)d", concat("a", capture(concat("b", changeMatchingOptions( - matchingOptions(adding: .caseInsensitive), - isIsolated: true, "c"))), "d"), + "a(b(?i)c)d", concat( + "a", + capture(concat( + "b", + changeMatchingOptions(matchingOptions(adding: .caseInsensitive)), + "c" + )), + "d" + ), captures: .atom() ) parseTest( - "(a(?i)b(c)d)", capture(concat("a", changeMatchingOptions( - matchingOptions(adding: .caseInsensitive), - isIsolated: true, concat("b", capture("c"), "d")))), + "(a(?i)b(c)d)", capture(concat( + "a", + changeMatchingOptions(matchingOptions(adding: .caseInsensitive)), + "b", + capture("c"), + "d" + )), captures: .tuple(.atom(), .atom()) ) parseTest( - "(a(?i)b(?#hello)c)", capture(concat("a", changeMatchingOptions( - matchingOptions(adding: .caseInsensitive), - isIsolated: true, concat("b", "c")))), + "(a(?i)b(?#hello)c)", capture(concat( + "a", + changeMatchingOptions(matchingOptions(adding: .caseInsensitive)), + "b", + "c" + )), captures: .atom() ) - // TODO: This is Oniguruma's behavior, but PCRE treats it as: - // ab(?i:c)|(?i:def)|(?i:gh) - // instead. We ought to have a mode to emulate that. - parseTest("ab(?i)c|def|gh", concat("a", "b", changeMatchingOptions( - matchingOptions(adding: .caseInsensitive), isIsolated: true, - alt("c", concat("d", "e", "f"), concat("g", "h"))))) + parseTest("ab(?i)c|def|gh", alt( + concat( + "a", + "b", + changeMatchingOptions(matchingOptions(adding: .caseInsensitive)), + "c" + ), + concat("d", "e", "f"), + concat("g", "h") + )) - parseTest("(a|b(?i)c|d)", capture(alt("a", concat("b", changeMatchingOptions( - matchingOptions(adding: .caseInsensitive), isIsolated: true, - alt("c", "d"))))), - captures: .atom()) + parseTest("(a|b(?i)c|d)", capture(alt( + "a", + concat( + "b", + changeMatchingOptions(matchingOptions(adding: .caseInsensitive)), + "c" + ), + "d" + )), captures: .atom()) // MARK: References @@ -1479,149 +1475,149 @@ extension RegexTests { parseTest("[(?#abc)]", charClass("(", "?", "#", "a", "b", "c", ")")) parseTest("# abc", concat("#", " ", "a", "b", "c")) - parseTest("(?x) # hello", changeMatchingOptions(matchingOptions( - adding: .extended), isIsolated: true, empty())) - parseTest("(?xx) # hello", changeMatchingOptions(matchingOptions( - adding: .extraExtended), isIsolated: true, empty())) - parseTest("(?x) \\# abc", changeMatchingOptions(matchingOptions( - adding: .extended), isIsolated: true, concat("#", "a", "b", "c"))) - parseTest("(?xx) \\ ", changeMatchingOptions(matchingOptions( - adding: .extraExtended), isIsolated: true, concat(" "))) + // MARK: Matching option changing parseTest( - "(?x) a (?^) b", - changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - concat( - "a", - changeMatchingOptions( - unsetMatchingOptions(), isIsolated: true, concat(" ", "b")) - ) - ) + "(?x) # hello", + changeMatchingOptions(matchingOptions(adding: .extended)) ) - - // End of line comments aren't applicable in custom char classes. - // TODO: ICU supports this. parseTest( - "(?x)[ # abc]", changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - charClass("#", "a", "b", "c")) + "(?xx) # hello", + changeMatchingOptions(matchingOptions(adding: .extraExtended)) ) + parseTest("(?x) \\# abc", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + "#", "a", "b", "c" + )) + parseTest("(?xx) \\ ", concat( + changeMatchingOptions(matchingOptions(adding: .extraExtended)), " " + )) parseTest( - "(?x)a b c[d e f]", changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - concat("a", "b", "c", charClass("d", "e", "f"))) - ) - parseTest( - "(?xx)a b c[d e f]", changeMatchingOptions( - matchingOptions(adding: .extraExtended), isIsolated: true, - concat("a", "b", "c", charClass("d", "e", "f"))) - ) - parseTest( - "(?x)a b c(?-x)d e f", changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - concat("a", "b", "c", - changeMatchingOptions(matchingOptions(removing: .extended), - isIsolated: true, concat("d", " ", "e", " ", "f")))) - ) - parseTest( - "(?x)a b c(?-xx)d e f", changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - concat("a", "b", "c", - changeMatchingOptions(matchingOptions(removing: .extraExtended), - isIsolated: true, concat("d", " ", "e", " ", "f")))) - ) - parseTest( - "(?xx)a b c(?-x)d e f", changeMatchingOptions( - matchingOptions(adding: .extraExtended), isIsolated: true, - concat("a", "b", "c", - changeMatchingOptions(matchingOptions(removing: .extended), - isIsolated: true, concat("d", " ", "e", " ", "f")))) - ) - parseTest( - "(?x)a b c(?^i)d e f", changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - concat("a", "b", "c", - changeMatchingOptions(unsetMatchingOptions(adding: .caseInsensitive), - isIsolated: true, concat("d", " ", "e", " ", "f")))) - ) - parseTest( - "(?x)a b c(?^x)d e f", changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - concat("a", "b", "c", - changeMatchingOptions(unsetMatchingOptions(adding: .extended), - isIsolated: true, concat("d", "e", "f")))) - ) - parseTest( - "(?:(?x)a b c)d e f", concat(nonCapture(changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - concat("a", "b", "c"))), "d", " ", "e", " ", "f") - ) - parseTest( - "(?x:a b c)# hi", concat(changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: false, - concat("a", "b", "c")), "#", " ", "h", "i") + "(?x) a (?^) b", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + "a", + changeMatchingOptions(unsetMatchingOptions()), + " ", "b" + ) ) - parseTest( - "(?x-x)a b c", changeMatchingOptions( - matchingOptions(adding: .extended, removing: .extended), isIsolated: true, - concat("a", " ", "b", " ", "c")) - ) - parseTest( - "(?xxx-x)a b c", changeMatchingOptions( - matchingOptions(adding: .extraExtended, .extended, removing: .extended), isIsolated: true, - concat("a", " ", "b", " ", "c")) - ) - parseTest( - "(?xx-i)a b c", changeMatchingOptions( - matchingOptions(adding: .extraExtended, removing: .caseInsensitive), isIsolated: true, - concat("a", "b", "c")) + // End of line comments aren't applicable in custom char classes. + // TODO: ICU supports this. + parseTest("(?x)[ # abc]", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + charClass("#", "a", "b", "c") + )) + + parseTest("(?x)a b c[d e f]", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + "a", "b", "c", charClass("d", "e", "f") + )) + parseTest("(?xx)a b c[d e f]", concat( + changeMatchingOptions(matchingOptions(adding: .extraExtended)), + "a", "b", "c", charClass("d", "e", "f") + )) + parseTest("(?x)a b c(?-x)d e f", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + "a", "b", "c", + changeMatchingOptions(matchingOptions(removing: .extended)), + "d", " ", "e", " ", "f" + )) + parseTest("(?x)a b c(?-xx)d e f", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + "a", "b", "c", + changeMatchingOptions(matchingOptions(removing: .extraExtended)), + "d", " ", "e", " ", "f" + )) + parseTest("(?xx)a b c(?-x)d e f", concat( + changeMatchingOptions(matchingOptions(adding: .extraExtended)), + "a", "b", "c", + changeMatchingOptions(matchingOptions(removing: .extended)), + "d", " ", "e", " ", "f" + )) + parseTest("(?x)a b c(?^i)d e f", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + "a", "b", "c", + changeMatchingOptions(unsetMatchingOptions(adding: .caseInsensitive)), + "d", " ", "e", " ", "f" + )) + parseTest("(?x)a b c(?^x)d e f", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + "a", "b", "c", + changeMatchingOptions(unsetMatchingOptions(adding: .extended)), + "d", "e", "f" + )) + parseTest("(?:(?x)a b c)d e f", concat( + nonCapture(concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + "a", "b", "c" + )), + "d", " ", "e", " ", "f" + )) + parseTest("(?x:a b c)# hi", concat(changeMatchingOptions( + matchingOptions(adding: .extended), + concat("a", "b", "c")), "#", " ", "h", "i") ) - // PCRE states that whitespace seperating quantifiers is permitted under - // extended syntax http://pcre.org/current/doc/html/pcre2api.html#SEC20 - parseTest( - "(?x)a *", + parseTest("(?x-x)a b c", concat( changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - zeroOrMore(of: "a")) - ) - parseTest( - "(?x)a + ?", + matchingOptions(adding: .extended, removing: .extended) + ), + "a", " ", "b", " ", "c" + )) + parseTest("(?xxx-x)a b c", concat( changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - oneOrMore(.reluctant, of: "a")) - ) - parseTest( - "(?x)a {2,4}", + matchingOptions(adding: .extraExtended, .extended, removing: .extended) + ), + "a", " ", "b", " ", "c" + )) + parseTest("(?xx-i)a b c", concat( changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - quantRange(2 ... 4, of: "a")) - ) + matchingOptions(adding: .extraExtended, removing: .caseInsensitive) + ), + "a", "b", "c" + )) + + // PCRE states that whitespace seperating quantifiers is permitted under + // extended syntax http://pcre.org/current/doc/html/pcre2api.html#SEC20 + parseTest("(?x)a *", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + zeroOrMore(of: "a") + )) + parseTest("(?x)a + ?", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + oneOrMore(.reluctant, of: "a") + )) + parseTest("(?x)a {2,4}", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + quantRange(2 ... 4, of: "a") + )) // PCRE states that whitespace won't be ignored within a range. // http://pcre.org/current/doc/html/pcre2api.html#SEC20 // TODO: We ought to warn on this, and produce a range anyway. - parseTest( - "(?x)a{1, 3}", - changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - concat("a", "{", "1", ",", "3", "}")) - ) + parseTest("(?x)a{1, 3}", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + "a", "{", "1", ",", "3", "}" + )) // Test that we cover the list of whitespace characters covered by PCRE. parseTest( "(?x)a\t\u{A}\u{B}\u{C}\u{D}\u{85}\u{200E}\u{200F}\u{2028}\u{2029} b", - changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, concat("a", "b")) - ) + concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + "a", "b" + )) parseTest( "(?x)[a\t\u{A}\u{B}\u{C}\u{D}\u{85}\u{200E}\u{200F}\u{2028}\u{2029} b]", - changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, charClass("a", "b")) - ) + concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + charClass("a", "b") + )) + + parseTest(#"(?i:)?"#, zeroOrOne(of: changeMatchingOptions( + matchingOptions(adding: .caseInsensitive), empty() + ))) // Test multi-line comment handling. parseTest( @@ -1843,10 +1839,10 @@ extension RegexTests { parseWithDelimitersTest("#|[a b]|#", charClass("a", "b")) parseWithDelimitersTest( - "#|(?-x)[a b]|#", changeMatchingOptions( - matchingOptions(removing: .extended), isIsolated: true, - charClass("a", " ", "b")) - ) + "#|(?-x)[a b]|#", concat( + changeMatchingOptions(matchingOptions(removing: .extended)), + charClass("a", " ", "b") + )) parseWithDelimitersTest("#|[[a ] b]|#", charClass(charClass("a"), "b")) // Non-semantic whitespace between quantifier characters for consistency @@ -1856,8 +1852,7 @@ extension RegexTests { // End-of-line comments aren't enabled by default in experimental syntax. parseWithDelimitersTest("#|#abc|#", concat("#", "a", "b", "c")) parseWithDelimitersTest("#|(?x)#abc|#", changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, - empty()) + matchingOptions(adding: .extended)) ) parseWithDelimitersTest("#|||#", alt(empty(), empty())) @@ -1913,8 +1908,7 @@ extension RegexTests { (?^) # comment /# - """, changeMatchingOptions( - unsetMatchingOptions(), isIsolated: true, empty()) + """, changeMatchingOptions(unsetMatchingOptions()) ) // (?x) has no effect. @@ -1923,8 +1917,7 @@ extension RegexTests { (?x) # comment /# - """, changeMatchingOptions( - matchingOptions(adding: .extended), isIsolated: true, empty()) + """, changeMatchingOptions(matchingOptions(adding: .extended)) ) // MARK: Delimiter skipping: Make sure we can skip over the ending delimiter @@ -2328,17 +2321,18 @@ extension RegexTests { diagnosticTest(#"\\#u{E9}"#, .invalidEscape("é")) diagnosticTest(#"\˂"#, .invalidEscape("˂")) - // MARK: Text Segment options + // MARK: Matching options diagnosticTest("(?-y{g})", .cannotRemoveTextSegmentOptions) diagnosticTest("(?-y{w})", .cannotRemoveTextSegmentOptions) - // MARK: Semantic Level options - diagnosticTest("(?-X)", .cannotRemoveSemanticsOptions) diagnosticTest("(?-u)", .cannotRemoveSemanticsOptions) diagnosticTest("(?-b)", .cannotRemoveSemanticsOptions) + diagnosticTest("(?a)", .unknownGroupKind("?a")) + diagnosticTest("(?y{)", .expected("g")) + // Extended syntax may not be removed in multi-line mode. diagnosticWithDelimitersTest(""" #/ @@ -2406,6 +2400,7 @@ extension RegexTests { diagnosticTest(#"(?^-)"#, .cannotRemoveMatchingOptionsAfterCaret) diagnosticTest(#"(?^i-"#, .cannotRemoveMatchingOptionsAfterCaret) diagnosticTest(#"(?^i-m)"#, .cannotRemoveMatchingOptionsAfterCaret) + diagnosticTest(#"(?i)?"#, .notQuantifiable) // MARK: References @@ -2438,7 +2433,7 @@ extension RegexTests { diagnosticTest(#"(?(1)a|b|c)"#, .tooManyBranchesInConditional(3)) diagnosticTest(#"(?(1)||)"#, .tooManyBranchesInConditional(3)) - diagnosticTest(#"(?(?i))"#, .unsupportedCondition("implicitly scoped group")) + diagnosticTest(#"(?(?i))"#, .unknownGroupKind("?(")) // MARK: Callouts From 4428e7f0ac58981ee377f25640b93a8c3a882f88 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 14 Apr 2022 14:24:00 -0500 Subject: [PATCH 067/133] Move RegexComponent conformances to RegexBuilder (#279) --- Sources/RegexBuilder/DSL.swift | 34 ++++++++++++++++++++++ Sources/_StringProcessing/Regex/Core.swift | 34 ---------------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 717e172b0..2befc08a4 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -32,6 +32,40 @@ extension _BuiltinRegexComponent { } } +// MARK: - Primitive regex components + +extension String: RegexComponent { + public typealias Output = Substring + + public var regex: Regex { + .init(node: .quotedLiteral(self)) + } +} + +extension Substring: RegexComponent { + public typealias Output = Substring + + public var regex: Regex { + .init(node: .quotedLiteral(String(self))) + } +} + +extension Character: RegexComponent { + public typealias Output = Substring + + public var regex: Regex { + .init(node: .atom(.char(self))) + } +} + +extension UnicodeScalar: RegexComponent { + public typealias Output = Substring + + public var regex: Regex { + .init(node: .atom(.scalar(self))) + } +} + // MARK: - Combinators // MARK: Concatenation diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index b77ee7ece..c9c46ad3f 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -97,37 +97,3 @@ extension Regex { } } - -// MARK: - Primitive regex components - -extension String: RegexComponent { - public typealias Output = Substring - - public var regex: Regex { - .init(node: .quotedLiteral(self)) - } -} - -extension Substring: RegexComponent { - public typealias Output = Substring - - public var regex: Regex { - .init(node: .quotedLiteral(String(self))) - } -} - -extension Character: RegexComponent { - public typealias Output = Substring - - public var regex: Regex { - .init(node: .atom(.char(self))) - } -} - -extension UnicodeScalar: RegexComponent { - public typealias Output = Substring - - public var regex: Regex { - .init(node: .atom(.scalar(self))) - } -} From 89da9f8ae22f4d2472939c1cbd620454a3aa1ef3 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 14 Apr 2022 21:50:58 +0100 Subject: [PATCH 068/133] Error on unknown character properties Previously we would form an `.other` character property kind for any unclassified properties, which crash at runtime as unsupported. Instead, switch to erroring on them. Eventually it would be nice if we could version this based on what the runtime being targeted supports. --- Sources/_RegexParser/Regex/AST/Atom.swift | 3 --- .../CharacterPropertyClassification.swift | 9 ++++--- .../Regex/Parse/Diagnostics.swift | 9 ++++--- .../_StringProcessing/ConsumerInterface.swift | 4 --- Tests/RegexTests/ParseTests.swift | 27 ++++++++++--------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Sources/_RegexParser/Regex/AST/Atom.swift b/Sources/_RegexParser/Regex/AST/Atom.swift index 9cc2e9a96..1f6043d72 100644 --- a/Sources/_RegexParser/Regex/AST/Atom.swift +++ b/Sources/_RegexParser/Regex/AST/Atom.swift @@ -401,9 +401,6 @@ extension AST.Atom.CharacterProperty { /// Some special properties implemented by PCRE and Oniguruma. case pcreSpecial(PCRESpecialCategory) case onigurumaSpecial(OnigurumaSpecialProperty) - - /// Unhandled properties. - case other(key: String?, value: String) } // TODO: erm, separate out or fold into something? splat it in? diff --git a/Sources/_RegexParser/Regex/Parse/CharacterPropertyClassification.swift b/Sources/_RegexParser/Regex/Parse/CharacterPropertyClassification.swift index e5b65a46c..911312121 100644 --- a/Sources/_RegexParser/Regex/Parse/CharacterPropertyClassification.swift +++ b/Sources/_RegexParser/Regex/Parse/CharacterPropertyClassification.swift @@ -397,8 +397,9 @@ extension Source { return .pcreSpecial(pcreSpecial) } - // Otherwise we don't know what this is. - return .other(key: nil, value: value) + // TODO: This should be versioned, and do we want a more lax behavior for + // the runtime? + throw ParseError.unknownProperty(key: nil, value: value) } static func classifyCharacterProperty( @@ -435,6 +436,8 @@ extension Source { if let match = match { return match } - return .other(key: key, value: value) + // TODO: This should be versioned, and do we want a more lax behavior for + // the runtime? + throw ParseError.unknownProperty(key: key, value: value) } } diff --git a/Sources/_RegexParser/Regex/Parse/Diagnostics.swift b/Sources/_RegexParser/Regex/Parse/Diagnostics.swift index 621d6ea11..c3d74c30b 100644 --- a/Sources/_RegexParser/Regex/Parse/Diagnostics.swift +++ b/Sources/_RegexParser/Regex/Parse/Diagnostics.swift @@ -57,8 +57,8 @@ enum ParseError: Error, Hashable { case expectedCustomCharacterClassMembers case invalidCharacterClassRangeOperand - case invalidPOSIXSetName(String) case emptyProperty + case unknownProperty(key: String?, value: String) case expectedGroupSpecifier case unbalancedEndOfGroup @@ -142,10 +142,13 @@ extension ParseError: CustomStringConvertible { return "expected custom character class members" case .invalidCharacterClassRangeOperand: return "invalid character class range" - case let .invalidPOSIXSetName(n): - return "invalid character set name: '\(n)'" case .emptyProperty: return "empty property" + case .unknownProperty(let key, let value): + if let key = key { + return "unknown character property '\(key)=\(value)'" + } + return "unknown character property '\(value)'" case .expectedGroupSpecifier: return "expected group specifier" case .unbalancedEndOfGroup: diff --git a/Sources/_StringProcessing/ConsumerInterface.swift b/Sources/_StringProcessing/ConsumerInterface.swift index b49804ca1..3c84195aa 100644 --- a/Sources/_StringProcessing/ConsumerInterface.swift +++ b/Sources/_StringProcessing/ConsumerInterface.swift @@ -423,10 +423,6 @@ extension AST.Atom.CharacterProperty { case .onigurumaSpecial(let s): throw Unsupported("TODO: map Oniguruma special: \(s)") - - case let .other(key, value): - throw Unsupported( - "TODO: map other \(key ?? "")=\(value)") } }() diff --git a/Tests/RegexTests/ParseTests.swift b/Tests/RegexTests/ParseTests.swift index bdae250ba..4043e4ccb 100644 --- a/Tests/RegexTests/ParseTests.swift +++ b/Tests/RegexTests/ParseTests.swift @@ -501,7 +501,6 @@ extension RegexTests { parseTest(#"[[:a]]"#, charClass(charClass(":", "a"))) parseTest(#"[[:}]]"#, charClass(charClass(":", "}"))) parseTest(#"[[:{]]"#, charClass(charClass(":", "{"))) - parseTest(#"[[:{:]]"#, charClass(posixProp_m(.other(key: nil, value: "{")))) parseTest(#"[[:}:]]"#, charClass(charClass(":", "}", ":"))) parseTest( @@ -1141,14 +1140,6 @@ extension RegexTests { #"\p{C}+"#, oneOrMore(of: prop(.generalCategory(.other)))) - // TODO: Start erroring on these? - parseTest(#"\p{Lx}"#, prop(.other(key: nil, value: "Lx"))) - parseTest(#"\p{gcL}"#, prop(.other(key: nil, value: "gcL"))) - parseTest(#"\p{x=y}"#, prop(.other(key: "x", value: "y"))) - parseTest(#"\p{aaa(b)}"#, prop(.other(key: nil, value: "aaa(b)"))) - parseTest("[[:a():]]", charClass(posixProp_m(.other(key: nil, value: "a()")))) - parseTest(#"\p{aaa\p{b}}"#, concat(prop(.other(key: nil, value: #"aaa\p{b"#)), "}")) - // UAX44-LM3 means all of the below are equivalent. let lowercaseLetter = prop(.generalCategory(.lowercaseLetter)) parseTest(#"\p{ll}"#, lowercaseLetter) @@ -2231,12 +2222,12 @@ extension RegexTests { diagnosticTest(#"\x{5"#, .expected("}")) diagnosticTest(#"\N{A"#, .expected("}")) diagnosticTest(#"\N{U+A"#, .expected("}")) - diagnosticTest(#"\p{a"#, .expected("}")) + diagnosticTest(#"\p{a"#, .unknownProperty(key: nil, value: "a")) diagnosticTest(#"\p{a="#, .emptyProperty) diagnosticTest(#"\p{a=}"#, .emptyProperty) - diagnosticTest(#"\p{a=b"#, .expected("}")) - diagnosticTest(#"\p{aaa[b]}"#, .expected("}")) - diagnosticTest(#"\p{a=b=c}"#, .expected("}")) + diagnosticTest(#"\p{a=b"#, .unknownProperty(key: "a", value: "b")) + diagnosticTest(#"\p{aaa[b]}"#, .unknownProperty(key: nil, value: "aaa")) + diagnosticTest(#"\p{a=b=c}"#, .unknownProperty(key: "a", value: "b")) diagnosticTest(#"(?#"#, .expected(")")) diagnosticTest(#"(?x"#, .expected(")")) @@ -2321,6 +2312,16 @@ extension RegexTests { diagnosticTest(#"\\#u{E9}"#, .invalidEscape("é")) diagnosticTest(#"\˂"#, .invalidEscape("˂")) + // MARK: Character properties + + diagnosticTest(#"\p{Lx}"#, .unknownProperty(key: nil, value: "Lx")) + diagnosticTest(#"\p{gcL}"#, .unknownProperty(key: nil, value: "gcL")) + diagnosticTest(#"\p{x=y}"#, .unknownProperty(key: "x", value: "y")) + diagnosticTest(#"\p{aaa(b)}"#, .unknownProperty(key: nil, value: "aaa(b)")) + diagnosticTest("[[:a():]]", .unknownProperty(key: nil, value: "a()")) + diagnosticTest(#"\p{aaa\p{b}}"#, .unknownProperty(key: nil, value: #"aaa\p{b"#)) + diagnosticTest(#"[[:{:]]"#, .unknownProperty(key: nil, value: "{")) + // MARK: Matching options diagnosticTest("(?-y{g})", .cannotRemoveTextSegmentOptions) From da89bf766c6c73206062db954ab6c13b14f488a9 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 14 Apr 2022 18:16:41 -0500 Subject: [PATCH 069/133] Rename RegexComponent.Output (#281) --- .../Participants/RegexParticipant.swift | 2 +- Sources/RegexBuilder/Anchor.swift | 4 +- Sources/RegexBuilder/DSL.swift | 6 +- Sources/RegexBuilder/Match.swift | 8 +- Sources/RegexBuilder/Variadics.swift | 828 +++++++++--------- .../VariadicsGenerator.swift | 2 +- .../Algorithms/Consumers/RegexConsumer.swift | 2 +- .../Algorithms/Matching/FirstMatch.swift | 2 +- .../Algorithms/Matching/MatchReplace.swift | 6 +- .../Algorithms/Matching/Matches.swift | 4 +- Sources/_StringProcessing/Regex/Core.swift | 4 +- .../Regex/DSLConsumers.swift | 6 +- Sources/_StringProcessing/Regex/Match.swift | 8 +- Sources/_StringProcessing/Regex/Options.swift | 22 +- .../_CharacterClassModel.swift | 4 +- Tests/RegexBuilderTests/AlgorithmsTests.swift | 2 +- Tests/RegexBuilderTests/CustomTests.swift | 8 +- Tests/RegexBuilderTests/RegexDSLTests.swift | 24 +- 18 files changed, 471 insertions(+), 471 deletions(-) diff --git a/Sources/Exercises/Participants/RegexParticipant.swift b/Sources/Exercises/Participants/RegexParticipant.swift index 6fddc0914..6c53b3adf 100644 --- a/Sources/Exercises/Participants/RegexParticipant.swift +++ b/Sources/Exercises/Participants/RegexParticipant.swift @@ -62,7 +62,7 @@ private func extractFromCaptures( private func graphemeBreakPropertyData( forLine line: String, using regex: RP -) -> GraphemeBreakEntry? where RP.Output == (Substring, Substring, Substring?, Substring) { +) -> GraphemeBreakEntry? where RP.RegexOutput == (Substring, Substring, Substring?, Substring) { line.wholeMatch(of: regex).map(\.output).flatMap(extractFromCaptures) } diff --git a/Sources/RegexBuilder/Anchor.swift b/Sources/RegexBuilder/Anchor.swift index 7933b987a..50129b94d 100644 --- a/Sources/RegexBuilder/Anchor.swift +++ b/Sources/RegexBuilder/Anchor.swift @@ -119,7 +119,7 @@ public struct Lookahead: _BuiltinRegexComponent { public init( _ component: R, negative: Bool = false - ) where R.Output == Output { + ) where R.RegexOutput == Output { self.init(node: .nonCapturingGroup( negative ? .negativeLookahead : .lookahead, component.regex.root)) } @@ -127,7 +127,7 @@ public struct Lookahead: _BuiltinRegexComponent { public init( negative: Bool = false, @RegexComponentBuilder _ component: () -> R - ) where R.Output == Output { + ) where R.RegexOutput == Output { self.init(node: .nonCapturingGroup( negative ? .negativeLookahead : .lookahead, component().regex.root)) } diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 2befc08a4..39a62984f 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -15,7 +15,7 @@ import _RegexParser extension Regex { public init( @RegexComponentBuilder _ content: () -> Content - ) where Content.Output == Output { + ) where Content.RegexOutput == Output { self = content().regex } } @@ -23,7 +23,7 @@ extension Regex { // A convenience protocol for builtin regex components that are initialized with // a `DSLTree` node. internal protocol _BuiltinRegexComponent: RegexComponent { - init(_ regex: Regex) + init(_ regex: Regex) } extension _BuiltinRegexComponent { @@ -224,7 +224,7 @@ public struct AlternationBuilder { @_disfavoredOverload public static func buildPartialBlock( first component: R - ) -> ChoiceOf { + ) -> ChoiceOf { .init(component.regex) } diff --git a/Sources/RegexBuilder/Match.swift b/Sources/RegexBuilder/Match.swift index 32dc889d9..1b4b3951b 100644 --- a/Sources/RegexBuilder/Match.swift +++ b/Sources/RegexBuilder/Match.swift @@ -15,14 +15,14 @@ extension String { @available(SwiftStdlib 5.7, *) public func wholeMatch( @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? { + ) -> Regex.Match? { wholeMatch(of: content()) } @available(SwiftStdlib 5.7, *) public func prefixMatch( @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? { + ) -> Regex.Match? { prefixMatch(of: content()) } } @@ -31,14 +31,14 @@ extension Substring { @available(SwiftStdlib 5.7, *) public func wholeMatch( @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? { + ) -> Regex.Match? { wholeMatch(of: content()) } @available(SwiftStdlib 5.7, *) public func prefixMatch( @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? { + ) -> Regex.Match? { prefixMatch(of: content()) } } diff --git a/Sources/RegexBuilder/Variadics.swift b/Sources/RegexBuilder/Variadics.swift index 2f4a6240a..e7bf02237 100644 --- a/Sources/RegexBuilder/Variadics.swift +++ b/Sources/RegexBuilder/Variadics.swift @@ -17,462 +17,462 @@ import _RegexParser extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0)> where R0.Output == W0, R1.Output == (W1, C0) { + ) -> Regex<(Substring, C0)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1)> where R0.Output == W0, R1.Output == (W1, C0, C1) { + ) -> Regex<(Substring, C0, C1)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2) { + ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3) { + ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3, C4) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3, C4, C5) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1)> where R0.Output == (W0, C0), R1.Output == (W1, C1) { + ) -> Regex<(Substring, C0, C1)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2) { + ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3) { + ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2) { + ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3) { + ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3) { + ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7, C8) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7, C8) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7, C8, C9) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7, C8) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7, C8, C9) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Output == (W1, C8) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Output == (W1, C8, C9) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.Output == (W1, C9) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.RegexOutput == (W1, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex where R0.Output == W0 { + ) -> Regex where R0.RegexOutput == W0 { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0)> where R0.Output == (W0, C0) { + ) -> Regex<(Substring, C0)> where R0.RegexOutput == (W0, C0) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1)> where R0.Output == (W0, C0, C1) { + ) -> Regex<(Substring, C0, C1)> where R0.RegexOutput == (W0, C0, C1) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2)> where R0.Output == (W0, C0, C1, C2) { + ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == (W0, C0, C1, C2) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Output == (W0, C0, C1, C2, C3) { + ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0, C1, C2, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Output == (W0, C0, C1, C2, C3, C4) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } extension RegexComponentBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @@ -483,7 +483,7 @@ extension Optionally { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == Substring { + ) where RegexOutput == Substring { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) } } @@ -493,7 +493,7 @@ extension Optionally { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == Substring { + ) where RegexOutput == Substring { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } } @@ -510,7 +510,7 @@ extension ZeroOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == Substring { + ) where RegexOutput == Substring { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } } @@ -520,7 +520,7 @@ extension ZeroOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == Substring { + ) where RegexOutput == Substring { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } } @@ -531,7 +531,7 @@ extension OneOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == Substring { + ) where RegexOutput == Substring { self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) } } @@ -541,7 +541,7 @@ extension OneOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == Substring { + ) where RegexOutput == Substring { self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } } @@ -552,7 +552,7 @@ extension Repeat { public init( _ component: Component, count: Int - ) where Output == Substring { + ) where RegexOutput == Substring { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) @@ -562,7 +562,7 @@ extension Repeat { public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == Substring { + ) where RegexOutput == Substring { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) @@ -573,7 +573,7 @@ extension Repeat { _ component: Component, _ expression: R, _ behavior: QuantificationBehavior = .eagerly - ) where Output == Substring, R.Bound == Int { + ) where RegexOutput == Substring, R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0.. Component - ) where Output == Substring, R.Bound == Int { + ) where RegexOutput == Substring, R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?), Component.Output == (W, C0) { + ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) } } @@ -599,7 +599,7 @@ extension Optionally { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?), Component.Output == (W, C0) { + ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } } @@ -607,7 +607,7 @@ extension Optionally { extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?)> where Component.Output == (W, C0) { + ) -> Regex<(Substring, C0?)> where Component.RegexOutput == (W, C0) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } @@ -615,7 +615,7 @@ extension ZeroOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?), Component.Output == (W, C0) { + ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } } @@ -624,7 +624,7 @@ extension ZeroOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?), Component.Output == (W, C0) { + ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } } @@ -634,7 +634,7 @@ extension OneOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0), Component.Output == (W, C0) { + ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) } } @@ -643,7 +643,7 @@ extension OneOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0), Component.Output == (W, C0) { + ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } } @@ -653,7 +653,7 @@ extension Repeat { public init( _ component: Component, count: Int - ) where Output == (Substring, C0?), Component.Output == (W, C0) { + ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) @@ -662,7 +662,7 @@ extension Repeat { public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?), Component.Output == (W, C0) { + ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) @@ -672,7 +672,7 @@ extension Repeat { _ component: Component, _ expression: R, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?), Component.Output == (W, C0), R.Bound == Int { + ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0.. Component - ) where Output == (Substring, C0?), Component.Output == (W, C0), R.Bound == Int { + ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) } } @@ -697,7 +697,7 @@ extension Optionally { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } } @@ -705,7 +705,7 @@ extension Optionally { extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?)> where Component.Output == (W, C0, C1) { + ) -> Regex<(Substring, C0?, C1?)> where Component.RegexOutput == (W, C0, C1) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } @@ -713,7 +713,7 @@ extension ZeroOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } } @@ -722,7 +722,7 @@ extension ZeroOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } } @@ -732,7 +732,7 @@ extension OneOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1), Component.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) } } @@ -741,7 +741,7 @@ extension OneOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1), Component.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } } @@ -751,7 +751,7 @@ extension Repeat { public init( _ component: Component, count: Int - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) @@ -760,7 +760,7 @@ extension Repeat { public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) @@ -770,7 +770,7 @@ extension Repeat { _ component: Component, _ expression: R, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0.. Component - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) } } @@ -795,7 +795,7 @@ extension Optionally { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } } @@ -803,7 +803,7 @@ extension Optionally { extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Output == (W, C0, C1, C2) { + ) -> Regex<(Substring, C0?, C1?, C2?)> where Component.RegexOutput == (W, C0, C1, C2) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } @@ -811,7 +811,7 @@ extension ZeroOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } } @@ -820,7 +820,7 @@ extension ZeroOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } } @@ -830,7 +830,7 @@ extension OneOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1, C2), Component.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) } } @@ -839,7 +839,7 @@ extension OneOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2), Component.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } } @@ -849,7 +849,7 @@ extension Repeat { public init( _ component: Component, count: Int - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) @@ -858,7 +858,7 @@ extension Repeat { public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) @@ -868,7 +868,7 @@ extension Repeat { _ component: Component, _ expression: R, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0.. Component - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) } } @@ -893,7 +893,7 @@ extension Optionally { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } } @@ -901,7 +901,7 @@ extension Optionally { extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Output == (W, C0, C1, C2, C3) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.RegexOutput == (W, C0, C1, C2, C3) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } @@ -909,7 +909,7 @@ extension ZeroOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } } @@ -918,7 +918,7 @@ extension ZeroOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } } @@ -928,7 +928,7 @@ extension OneOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1, C2, C3), Component.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) } } @@ -937,7 +937,7 @@ extension OneOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3), Component.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } } @@ -947,7 +947,7 @@ extension Repeat { public init( _ component: Component, count: Int - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) @@ -956,7 +956,7 @@ extension Repeat { public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) @@ -966,7 +966,7 @@ extension Repeat { _ component: Component, _ expression: R, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0.. Component - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) } } @@ -991,7 +991,7 @@ extension Optionally { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } } @@ -999,7 +999,7 @@ extension Optionally { extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Output == (W, C0, C1, C2, C3, C4) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } @@ -1007,7 +1007,7 @@ extension ZeroOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } } @@ -1016,7 +1016,7 @@ extension ZeroOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } } @@ -1026,7 +1026,7 @@ extension OneOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1, C2, C3, C4), Component.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) } } @@ -1035,7 +1035,7 @@ extension OneOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4), Component.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } } @@ -1045,7 +1045,7 @@ extension Repeat { public init( _ component: Component, count: Int - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) @@ -1054,7 +1054,7 @@ extension Repeat { public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) @@ -1064,7 +1064,7 @@ extension Repeat { _ component: Component, _ expression: R, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0.. Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) } } @@ -1089,7 +1089,7 @@ extension Optionally { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } } @@ -1097,7 +1097,7 @@ extension Optionally { extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } @@ -1105,7 +1105,7 @@ extension ZeroOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } } @@ -1114,7 +1114,7 @@ extension ZeroOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } } @@ -1124,7 +1124,7 @@ extension OneOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1, C2, C3, C4, C5), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) } } @@ -1133,7 +1133,7 @@ extension OneOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } } @@ -1143,7 +1143,7 @@ extension Repeat { public init( _ component: Component, count: Int - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) @@ -1152,7 +1152,7 @@ extension Repeat { public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) @@ -1162,7 +1162,7 @@ extension Repeat { _ component: Component, _ expression: R, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0.. Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) } } @@ -1187,7 +1187,7 @@ extension Optionally { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } } @@ -1195,7 +1195,7 @@ extension Optionally { extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } @@ -1203,7 +1203,7 @@ extension ZeroOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } } @@ -1212,7 +1212,7 @@ extension ZeroOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } } @@ -1222,7 +1222,7 @@ extension OneOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) } } @@ -1231,7 +1231,7 @@ extension OneOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } } @@ -1241,7 +1241,7 @@ extension Repeat { public init( _ component: Component, count: Int - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) @@ -1250,7 +1250,7 @@ extension Repeat { public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) @@ -1260,7 +1260,7 @@ extension Repeat { _ component: Component, _ expression: R, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0.. Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) } } @@ -1285,7 +1285,7 @@ extension Optionally { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } } @@ -1293,7 +1293,7 @@ extension Optionally { extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } @@ -1301,7 +1301,7 @@ extension ZeroOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } } @@ -1310,7 +1310,7 @@ extension ZeroOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } } @@ -1320,7 +1320,7 @@ extension OneOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) } } @@ -1329,7 +1329,7 @@ extension OneOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } } @@ -1339,7 +1339,7 @@ extension Repeat { public init( _ component: Component, count: Int - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) @@ -1348,7 +1348,7 @@ extension Repeat { public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) @@ -1358,7 +1358,7 @@ extension Repeat { _ component: Component, _ expression: R, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0.. Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) } } @@ -1383,7 +1383,7 @@ extension Optionally { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } } @@ -1391,7 +1391,7 @@ extension Optionally { extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } @@ -1399,7 +1399,7 @@ extension ZeroOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } } @@ -1408,7 +1408,7 @@ extension ZeroOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } } @@ -1418,7 +1418,7 @@ extension OneOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) } } @@ -1427,7 +1427,7 @@ extension OneOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } } @@ -1437,7 +1437,7 @@ extension Repeat { public init( _ component: Component, count: Int - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) @@ -1446,7 +1446,7 @@ extension Repeat { public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) @@ -1456,7 +1456,7 @@ extension Repeat { _ component: Component, _ expression: R, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0.. Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) } } @@ -1481,7 +1481,7 @@ extension Optionally { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } } @@ -1489,7 +1489,7 @@ extension Optionally { extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } @@ -1497,7 +1497,7 @@ extension ZeroOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } } @@ -1506,7 +1506,7 @@ extension ZeroOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } } @@ -1516,7 +1516,7 @@ extension OneOrMore { public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) } } @@ -1525,7 +1525,7 @@ extension OneOrMore { public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } } @@ -1535,7 +1535,7 @@ extension Repeat { public init( _ component: Component, count: Int - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) @@ -1544,7 +1544,7 @@ extension Repeat { public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) @@ -1554,7 +1554,7 @@ extension Repeat { _ component: Component, _ expression: R, _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0.. Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { + ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component - ) where Output == Substring { + ) where RegexOutput == Substring { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -1579,14 +1579,14 @@ extension Local { @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == Substring { + ) where RegexOutput == Substring { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } extension Local { public init( _ component: Component - ) where Output == (Substring, C0), Component.Output == (W, C0) { + ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -1594,14 +1594,14 @@ extension Local { extension Local { public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0), Component.Output == (W, C0) { + ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } extension Local { public init( _ component: Component - ) where Output == (Substring, C0, C1), Component.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -1609,14 +1609,14 @@ extension Local { extension Local { public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1), Component.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } extension Local { public init( _ component: Component - ) where Output == (Substring, C0, C1, C2), Component.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -1624,14 +1624,14 @@ extension Local { extension Local { public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2), Component.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } extension Local { public init( _ component: Component - ) where Output == (Substring, C0, C1, C2, C3), Component.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -1639,14 +1639,14 @@ extension Local { extension Local { public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3), Component.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } extension Local { public init( _ component: Component - ) where Output == (Substring, C0, C1, C2, C3, C4), Component.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -1654,14 +1654,14 @@ extension Local { extension Local { public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4), Component.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } extension Local { public init( _ component: Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -1669,14 +1669,14 @@ extension Local { extension Local { public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } extension Local { public init( _ component: Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -1684,14 +1684,14 @@ extension Local { extension Local { public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } extension Local { public init( _ component: Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -1699,14 +1699,14 @@ extension Local { extension Local { public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } extension Local { public init( _ component: Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -1714,14 +1714,14 @@ extension Local { extension Local { public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } extension Local { public init( _ component: Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -1729,7 +1729,7 @@ extension Local { extension Local { public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } @@ -1743,498 +1743,498 @@ extension AlternationBuilder { extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0) { + ) -> ChoiceOf<(Substring, C0?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1) { + ) -> ChoiceOf<(Substring, C0?, C1?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2) { + ) -> ChoiceOf<(Substring, C0?, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3) { + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4) { + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5) { + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6) { + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0) { + ) -> ChoiceOf<(Substring, C0)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1) { + ) -> ChoiceOf<(Substring, C0, C1?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2) { + ) -> ChoiceOf<(Substring, C0, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3) { + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4) { + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5) { + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6) { + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7) { + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1) { + ) -> ChoiceOf<(Substring, C0, C1)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2) { + ) -> ChoiceOf<(Substring, C0, C1, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3) { + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4) { + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5) { + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6) { + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7) { + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7, C8) { + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2) { + ) -> ChoiceOf<(Substring, C0, C1, C2)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7, C8) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7, C8, C9) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7, C8) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7, C8, C9) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7, C8) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7, C8, C9) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7, C8) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7, C8, C9) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7, C8) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7, C8, C9) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Output == (W1, C8) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Output == (W1, C8, C9) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.Output == (W1, C9) { + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.RegexOutput == (W1, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } extension AlternationBuilder { - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?)> where R: RegexComponent, R.Output == (W, C0) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?)> where R: RegexComponent, R.RegexOutput == (W, C0) { .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?)> where R: RegexComponent, R.Output == (W, C0, C1) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1) { .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?)> where R: RegexComponent, R.Output == (W, C0, C1, C2) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2) { .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3) { .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3, C4) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4) { .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3, C4, C5) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: .orderedChoice([regex.regex.root])) } } @@ -2244,14 +2244,14 @@ extension Capture { @_disfavoredOverload public init( _ component: R - ) where Output == (Substring, W), R.Output == W { + ) where RegexOutput == (Substring, W), R.RegexOutput == W { self.init(node: .capture(component.regex.root)) } @_disfavoredOverload public init( _ component: R, as reference: Reference - ) where Output == (Substring, W), R.Output == W { + ) where RegexOutput == (Substring, W), R.RegexOutput == W { self.init(node: .capture(reference: reference.id, component.regex.root)) } @@ -2259,7 +2259,7 @@ extension Capture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture), R.Output == W { + ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2272,7 +2272,7 @@ extension Capture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture), R.Output == W { + ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture( reference: reference.id, .transform( @@ -2288,7 +2288,7 @@ extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture), R.Output == W { + ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -2301,7 +2301,7 @@ extension TryCapture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture), R.Output == W { + ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture( reference: reference.id, .transform( @@ -2318,7 +2318,7 @@ extension Capture { @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W), R.Output == W { + ) where RegexOutput == (Substring, W), R.RegexOutput == W { self.init(node: .capture(component().regex.root)) } @@ -2326,7 +2326,7 @@ extension Capture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W), R.Output == W { + ) where RegexOutput == (Substring, W), R.RegexOutput == W { self.init(node: .capture( reference: reference.id, component().regex.root)) @@ -2336,7 +2336,7 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture), R.Output == W { + ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2349,7 +2349,7 @@ extension Capture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture), R.Output == W { + ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture( reference: reference.id, .transform( @@ -2365,7 +2365,7 @@ extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture), R.Output == W { + ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -2378,7 +2378,7 @@ extension TryCapture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture), R.Output == W { + ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture( reference: reference.id, .transform( @@ -2394,20 +2394,20 @@ extension TryCapture { extension Capture { public init( _ component: R - ) where Output == (Substring, W, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, W, C0), R.RegexOutput == (W, C0) { self.init(node: .capture(component.regex.root)) } public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, W, C0), R.RegexOutput == (W, C0) { self.init(node: .capture(reference: reference.id, component.regex.root)) } public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2419,7 +2419,7 @@ extension Capture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { self.init(node: .capture( reference: reference.id, .transform( @@ -2434,7 +2434,7 @@ extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -2446,7 +2446,7 @@ extension TryCapture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { self.init(node: .capture( reference: reference.id, .transform( @@ -2462,14 +2462,14 @@ extension TryCapture { extension Capture { public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, W, C0), R.RegexOutput == (W, C0) { self.init(node: .capture(component().regex.root)) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, W, C0), R.RegexOutput == (W, C0) { self.init(node: .capture( reference: reference.id, component().regex.root)) @@ -2478,7 +2478,7 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2490,7 +2490,7 @@ extension Capture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { self.init(node: .capture( reference: reference.id, .transform( @@ -2505,7 +2505,7 @@ extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -2517,7 +2517,7 @@ extension TryCapture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { self.init(node: .capture( reference: reference.id, .transform( @@ -2533,20 +2533,20 @@ extension TryCapture { extension Capture { public init( _ component: R - ) where Output == (Substring, W, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, W, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture(component.regex.root)) } public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, W, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture(reference: reference.id, component.regex.root)) } public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2558,7 +2558,7 @@ extension Capture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture( reference: reference.id, .transform( @@ -2573,7 +2573,7 @@ extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -2585,7 +2585,7 @@ extension TryCapture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture( reference: reference.id, .transform( @@ -2601,14 +2601,14 @@ extension TryCapture { extension Capture { public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, W, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture(component().regex.root)) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, W, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture( reference: reference.id, component().regex.root)) @@ -2617,7 +2617,7 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2629,7 +2629,7 @@ extension Capture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture( reference: reference.id, .transform( @@ -2644,7 +2644,7 @@ extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -2656,7 +2656,7 @@ extension TryCapture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture( reference: reference.id, .transform( @@ -2672,20 +2672,20 @@ extension TryCapture { extension Capture { public init( _ component: R - ) where Output == (Substring, W, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, W, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture(component.regex.root)) } public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, W, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture(reference: reference.id, component.regex.root)) } public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2697,7 +2697,7 @@ extension Capture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture( reference: reference.id, .transform( @@ -2712,7 +2712,7 @@ extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -2724,7 +2724,7 @@ extension TryCapture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture( reference: reference.id, .transform( @@ -2740,14 +2740,14 @@ extension TryCapture { extension Capture { public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, W, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture(component().regex.root)) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, W, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture( reference: reference.id, component().regex.root)) @@ -2756,7 +2756,7 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2768,7 +2768,7 @@ extension Capture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture( reference: reference.id, .transform( @@ -2783,7 +2783,7 @@ extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -2795,7 +2795,7 @@ extension TryCapture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture( reference: reference.id, .transform( @@ -2811,20 +2811,20 @@ extension TryCapture { extension Capture { public init( _ component: R - ) where Output == (Substring, W, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture(component.regex.root)) } public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture(reference: reference.id, component.regex.root)) } public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2836,7 +2836,7 @@ extension Capture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture( reference: reference.id, .transform( @@ -2851,7 +2851,7 @@ extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -2863,7 +2863,7 @@ extension TryCapture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture( reference: reference.id, .transform( @@ -2879,14 +2879,14 @@ extension TryCapture { extension Capture { public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture(component().regex.root)) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture( reference: reference.id, component().regex.root)) @@ -2895,7 +2895,7 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2907,7 +2907,7 @@ extension Capture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture( reference: reference.id, .transform( @@ -2922,7 +2922,7 @@ extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -2934,7 +2934,7 @@ extension TryCapture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture( reference: reference.id, .transform( @@ -2950,20 +2950,20 @@ extension TryCapture { extension Capture { public init( _ component: R - ) where Output == (Substring, W, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture(component.regex.root)) } public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture(reference: reference.id, component.regex.root)) } public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2975,7 +2975,7 @@ extension Capture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, .transform( @@ -2990,7 +2990,7 @@ extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3002,7 +3002,7 @@ extension TryCapture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, .transform( @@ -3018,14 +3018,14 @@ extension TryCapture { extension Capture { public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture(component().regex.root)) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, component().regex.root)) @@ -3034,7 +3034,7 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3046,7 +3046,7 @@ extension Capture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, .transform( @@ -3061,7 +3061,7 @@ extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3073,7 +3073,7 @@ extension TryCapture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, .transform( @@ -3089,20 +3089,20 @@ extension TryCapture { extension Capture { public init( _ component: R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture(component.regex.root)) } public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture(reference: reference.id, component.regex.root)) } public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3114,7 +3114,7 @@ extension Capture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, .transform( @@ -3129,7 +3129,7 @@ extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3141,7 +3141,7 @@ extension TryCapture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, .transform( @@ -3157,14 +3157,14 @@ extension TryCapture { extension Capture { public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture(component().regex.root)) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, component().regex.root)) @@ -3173,7 +3173,7 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3185,7 +3185,7 @@ extension Capture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, .transform( @@ -3200,7 +3200,7 @@ extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3212,7 +3212,7 @@ extension TryCapture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, .transform( @@ -3228,20 +3228,20 @@ extension TryCapture { extension Capture { public init( _ component: R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(component.regex.root)) } public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(reference: reference.id, component.regex.root)) } public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3253,7 +3253,7 @@ extension Capture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, .transform( @@ -3268,7 +3268,7 @@ extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3280,7 +3280,7 @@ extension TryCapture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, .transform( @@ -3296,14 +3296,14 @@ extension TryCapture { extension Capture { public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(component().regex.root)) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, component().regex.root)) @@ -3312,7 +3312,7 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3324,7 +3324,7 @@ extension Capture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, .transform( @@ -3339,7 +3339,7 @@ extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3351,7 +3351,7 @@ extension TryCapture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, .transform( @@ -3367,20 +3367,20 @@ extension TryCapture { extension Capture { public init( _ component: R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(component.regex.root)) } public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(reference: reference.id, component.regex.root)) } public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3392,7 +3392,7 @@ extension Capture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, .transform( @@ -3407,7 +3407,7 @@ extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3419,7 +3419,7 @@ extension TryCapture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, .transform( @@ -3435,14 +3435,14 @@ extension TryCapture { extension Capture { public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(component().regex.root)) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, component().regex.root)) @@ -3451,7 +3451,7 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3463,7 +3463,7 @@ extension Capture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, .transform( @@ -3478,7 +3478,7 @@ extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3490,7 +3490,7 @@ extension TryCapture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, .transform( @@ -3506,20 +3506,20 @@ extension TryCapture { extension Capture { public init( _ component: R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(component.regex.root)) } public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(reference: reference.id, component.regex.root)) } public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3531,7 +3531,7 @@ extension Capture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, .transform( @@ -3546,7 +3546,7 @@ extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3558,7 +3558,7 @@ extension TryCapture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, .transform( @@ -3574,14 +3574,14 @@ extension TryCapture { extension Capture { public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(component().regex.root)) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, component().regex.root)) @@ -3590,7 +3590,7 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3602,7 +3602,7 @@ extension Capture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, .transform( @@ -3617,7 +3617,7 @@ extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3629,7 +3629,7 @@ extension TryCapture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, .transform( @@ -3645,20 +3645,20 @@ extension TryCapture { extension Capture { public init( _ component: R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(component.regex.root)) } public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(reference: reference.id, component.regex.root)) } public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3670,7 +3670,7 @@ extension Capture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, .transform( @@ -3685,7 +3685,7 @@ extension TryCapture { public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3697,7 +3697,7 @@ extension TryCapture { _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, .transform( @@ -3713,14 +3713,14 @@ extension TryCapture { extension Capture { public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(component().regex.root)) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, component().regex.root)) @@ -3729,7 +3729,7 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3741,7 +3741,7 @@ extension Capture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, .transform( @@ -3756,7 +3756,7 @@ extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3768,7 +3768,7 @@ extension TryCapture { as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, .transform( diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index 5fbd2bf2d..1a0742f20 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -90,7 +90,7 @@ var standardError = StandardErrorStream() typealias Counter = Int64 let regexComponentProtocolName = "RegexComponent" -let outputAssociatedTypeName = "Output" +let outputAssociatedTypeName = "RegexOutput" let patternProtocolRequirementName = "regex" let regexTypeName = "Regex" let baseMatchTypeName = "Substring" diff --git a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift index 2718d520a..81f3ebb3e 100644 --- a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift +++ b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift @@ -37,7 +37,7 @@ extension RegexConsumer { // well, taking advantage of the fact that the captures can be ignored extension RegexConsumer: MatchingCollectionConsumer { - typealias Match = R.Output + typealias Match = R.RegexOutput func matchingConsuming( _ consumed: Consumed, in range: Range diff --git a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift index 1ad555e7d..093a47b71 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift @@ -56,7 +56,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// there isn't a match. public func firstMatch( of r: R - ) -> Regex.Match? { + ) -> Regex.Match? { let slice = self[...] return try? r.regex.firstMatch(in: slice.base) } diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift index 82ca00797..461c08e02 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift @@ -125,7 +125,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, - with replacement: (Regex.Match) throws -> Replacement, + with replacement: (Regex.Match) throws -> Replacement, subrange: Range, maxReplacements: Int = .max ) rethrows -> Self where Replacement.Element == Element { @@ -161,7 +161,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, - with replacement: (Regex.Match) throws -> Replacement, + with replacement: (Regex.Match) throws -> Replacement, maxReplacements: Int = .max ) rethrows -> Self where Replacement.Element == Element { try replacing( @@ -182,7 +182,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { @available(SwiftStdlib 5.7, *) public mutating func replace( _ regex: R, - with replacement: (Regex.Match) throws -> Replacement, + with replacement: (Regex.Match) throws -> Replacement, maxReplacements: Int = .max ) rethrows where Replacement.Element == Element { self = try replacing( diff --git a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift index 24cdbee0f..484737f05 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift @@ -202,13 +202,13 @@ extension BidirectionalCollection where SubSequence == Substring { // FIXME: Replace the returned value as `some Collection.Match> // when SE-0346 is enabled - func _matches(of r: R) -> [Regex.Match] { + func _matches(of r: R) -> [Regex.Match] { let slice = self[...] var start = self.startIndex let end = self.endIndex let regex = r.regex - var result = [Regex.Match]() + var result = [Regex.Match]() while start < end { guard let match = try? regex._firstMatch( slice.base, in: start.. { get } + associatedtype RegexOutput + var regex: Regex { get } } /// A regex represents a string processing algorithm. diff --git a/Sources/_StringProcessing/Regex/DSLConsumers.swift b/Sources/_StringProcessing/Regex/DSLConsumers.swift index 8bca244c2..c3dc6d88c 100644 --- a/Sources/_StringProcessing/Regex/DSLConsumers.swift +++ b/Sources/_StringProcessing/Regex/DSLConsumers.swift @@ -15,12 +15,12 @@ public protocol CustomRegexComponent: RegexComponent { _ input: String, startingAt index: String.Index, in bounds: Range - ) -> (upperBound: String.Index, output: Output)? + ) -> (upperBound: String.Index, output: RegexOutput)? } extension CustomRegexComponent { - public var regex: Regex { - Regex(node: .matcher(.init(Output.self), { input, index, bounds in + public var regex: Regex { + Regex(node: .matcher(.init(RegexOutput.self), { input, index, bounds in match(input, startingAt: index, in: bounds) })) } diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 8b37837e6..73ae62b7e 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -155,24 +155,24 @@ extension Regex { extension String { public func wholeMatch( of r: R - ) -> Regex.Match? { + ) -> Regex.Match? { try? r.regex.wholeMatch(in: self) } public func prefixMatch( of r: R - ) -> Regex.Match? { + ) -> Regex.Match? { try? r.regex.prefixMatch(in: self) } } extension Substring { public func wholeMatch( of r: R - ) -> Regex.Match? { + ) -> Regex.Match? { try? r.regex.wholeMatch(in: self) } public func prefixMatch( of r: R - ) -> Regex.Match? { + ) -> Regex.Match? { try? r.regex.prefixMatch(in: self) } } diff --git a/Sources/_StringProcessing/Regex/Options.swift b/Sources/_StringProcessing/Regex/Options.swift index 32e73b08c..8f48ba097 100644 --- a/Sources/_StringProcessing/Regex/Options.swift +++ b/Sources/_StringProcessing/Regex/Options.swift @@ -13,30 +13,30 @@ import _RegexParser extension RegexComponent { /// Returns a regular expression that ignores casing when matching. - public func ignoringCase(_ ignoreCase: Bool = true) -> Regex { + public func ignoringCase(_ ignoreCase: Bool = true) -> Regex { wrapInOption(.caseInsensitive, addingIf: ignoreCase) } /// Returns a regular expression that only matches ASCII characters as "word /// characters". - public func usingASCIIWordCharacters(_ useASCII: Bool = true) -> Regex { + public func usingASCIIWordCharacters(_ useASCII: Bool = true) -> Regex { wrapInOption(.asciiOnlyDigit, addingIf: useASCII) } /// Returns a regular expression that only matches ASCII characters as digits. - public func usingASCIIDigits(_ useASCII: Bool = true) -> Regex { + public func usingASCIIDigits(_ useASCII: Bool = true) -> Regex { wrapInOption(.asciiOnlyDigit, addingIf: useASCII) } /// Returns a regular expression that only matches ASCII characters as space /// characters. - public func usingASCIISpaces(_ useASCII: Bool = true) -> Regex { + public func usingASCIISpaces(_ useASCII: Bool = true) -> Regex { wrapInOption(.asciiOnlySpace, addingIf: useASCII) } /// Returns a regular expression that only matches ASCII characters when /// matching character classes. - public func usingASCIICharacterClasses(_ useASCII: Bool = true) -> Regex { + public func usingASCIICharacterClasses(_ useASCII: Bool = true) -> Regex { wrapInOption(.asciiOnlyPOSIXProps, addingIf: useASCII) } @@ -45,7 +45,7 @@ extension RegexComponent { /// /// This option is enabled by default; pass `false` to disable use of /// Unicode's word boundary algorithm. - public func usingUnicodeWordBoundaries(_ useUnicodeWordBoundaries: Bool = true) -> Regex { + public func usingUnicodeWordBoundaries(_ useUnicodeWordBoundaries: Bool = true) -> Regex { wrapInOption(.unicodeWordBoundaries, addingIf: useUnicodeWordBoundaries) } @@ -54,7 +54,7 @@ extension RegexComponent { /// /// - Parameter dotMatchesNewlines: A Boolean value indicating whether `.` /// should match a newline character. - public func dotMatchesNewlines(_ dotMatchesNewlines: Bool = true) -> Regex { + public func dotMatchesNewlines(_ dotMatchesNewlines: Bool = true) -> Regex { wrapInOption(.singleLine, addingIf: dotMatchesNewlines) } @@ -95,7 +95,7 @@ extension RegexComponent { /// // Prints "true" /// print(decomposed.contains(queRegexScalar)) /// // Prints "false" - public func matchingSemantics(_ semanticLevel: RegexSemanticLevel) -> Regex { + public func matchingSemantics(_ semanticLevel: RegexSemanticLevel) -> Regex { switch semanticLevel.base { case .graphemeCluster: return wrapInOption(.graphemeClusterSemantics, addingIf: true) @@ -139,7 +139,7 @@ extension RegexComponent { /// /// - Parameter matchLineEndings: A Boolean value indicating whether `^` and /// `$` should match the start and end of lines, respectively. - public func anchorsMatchLineEndings(_ matchLineEndings: Bool = true) -> Regex { + public func anchorsMatchLineEndings(_ matchLineEndings: Bool = true) -> Regex { wrapInOption(.multiline, addingIf: matchLineEndings) } @@ -153,7 +153,7 @@ extension RegexComponent { /// /// - Parameter useReluctantCaptures: A Boolean value indicating whether /// quantifiers should be reluctant by default. - public func reluctantCaptures(_ useReluctantCaptures: Bool = true) -> Regex { + public func reluctantCaptures(_ useReluctantCaptures: Bool = true) -> Regex { wrapInOption(.reluctantByDefault, addingIf: useReluctantCaptures) } } @@ -162,7 +162,7 @@ extension RegexComponent { extension RegexComponent { fileprivate func wrapInOption( _ option: AST.MatchingOption.Kind, - addingIf shouldAdd: Bool) -> Regex + addingIf shouldAdd: Bool) -> Regex { let sequence = shouldAdd ? AST.MatchingOptionSequence(adding: [.init(option, location: .fake)]) diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index 0c45d2b6c..e63423f8f 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -206,9 +206,9 @@ public struct _CharacterClassModel: Hashable { } extension _CharacterClassModel: RegexComponent { - public typealias Output = Substring + public typealias RegexOutput = Substring - public var regex: Regex { + public var regex: Regex { guard let ast = self.makeAST() else { fatalError("FIXME: extended AST?") } diff --git a/Tests/RegexBuilderTests/AlgorithmsTests.swift b/Tests/RegexBuilderTests/AlgorithmsTests.swift index fed584ff7..cf117690a 100644 --- a/Tests/RegexBuilderTests/AlgorithmsTests.swift +++ b/Tests/RegexBuilderTests/AlgorithmsTests.swift @@ -28,7 +28,7 @@ class RegexConsumerTests: XCTestCase { _ regex: R, input: String, result: String, - _ replace: (Regex.Match) -> String, + _ replace: (Regex.Match) -> String, file: StaticString = #file, line: UInt = #line ) { diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index 555ecb8ca..0ac6b46c5 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -15,7 +15,7 @@ import _StringProcessing // A nibbler processes a single character from a string private protocol Nibbler: CustomRegexComponent { - func nibble(_: Character) -> Output? + func nibble(_: Character) -> RegexOutput? } extension Nibbler { @@ -24,7 +24,7 @@ extension Nibbler { _ input: String, startingAt index: String.Index, in bounds: Range - ) -> (upperBound: String.Index, output: Output)? { + ) -> (upperBound: String.Index, output: RegexOutput)? { guard index != bounds.upperBound, let res = nibble(input[index]) else { return nil } @@ -35,7 +35,7 @@ extension Nibbler { // A number nibbler private struct Numbler: Nibbler { - typealias Output = Int + typealias RegexOutput = Int func nibble(_ c: Character) -> Int? { c.wholeNumberValue } @@ -43,7 +43,7 @@ private struct Numbler: Nibbler { // An ASCII value nibbler private struct Asciibbler: Nibbler { - typealias Output = UInt8 + typealias RegexOutput = UInt8 func nibble(_ c: Character) -> UInt8? { c.asciiValue } diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 0c0bf7c8f..b38b82a33 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -28,10 +28,10 @@ class RegexDSLTests: XCTestCase { if let expectedCaptures = maybeExpectedCaptures { let match = try XCTUnwrap(maybeMatch, file: file, line: line) XCTAssertTrue( - type(of: regex).Output.self == MatchType.self, + type(of: regex).RegexOutput.self == MatchType.self, """ Expected match type: \(MatchType.self) - Actual match type: \(type(of: regex).Output.self) + Actual match type: \(type(of: regex).RegexOutput.self) """) let captures = try XCTUnwrap(match.output as? MatchType, file: file, line: line) XCTAssertTrue( @@ -51,7 +51,7 @@ class RegexDSLTests: XCTestCase { TryCapture("1") { Int($0) } // Int } // Assert the inferred capture type. - let _: (Substring, Substring, Int).Type = type(of: regex).Output.self + let _: (Substring, Substring, Int).Type = type(of: regex).RegexOutput.self let maybeMatch = "ab1".wholeMatch(of: regex) let match = try XCTUnwrap(maybeMatch) XCTAssertTrue(match.output == ("ab1", "b", 1)) @@ -405,7 +405,7 @@ class RegexDSLTests: XCTestCase { // void. let regex = ZeroOrMore(.digit) // Assert the inferred capture type. - let _: Substring.Type = type(of: regex).Output.self + let _: Substring.Type = type(of: regex).RegexOutput.self let input = "123123" let match = try XCTUnwrap(input.wholeMatch(of: regex)?.output) XCTAssertTrue(match == input) @@ -454,7 +454,7 @@ class RegexDSLTests: XCTestCase { } } let _: (Substring, Substring, Substring).Type - = type(of: regex1).Output.self + = type(of: regex1).RegexOutput.self let regex2 = Regex { OneOrMore("a") Capture { @@ -465,7 +465,7 @@ class RegexDSLTests: XCTestCase { } } let _: (Substring, Substring, Int?).Type - = type(of: regex2).Output.self + = type(of: regex2).RegexOutput.self let regex3 = Regex { OneOrMore("a") Capture { @@ -477,7 +477,7 @@ class RegexDSLTests: XCTestCase { } } let _: (Substring, Substring, Int, Double?).Type - = type(of: regex3).Output.self + = type(of: regex3).RegexOutput.self let regex4 = Regex { OneOrMore("a") Capture { @@ -491,7 +491,7 @@ class RegexDSLTests: XCTestCase { } let _: ( Substring, Substring, Substring, Substring, Substring?).Type - = type(of: regex4).Output.self + = type(of: regex4).RegexOutput.self } func testUnicodeScalarPostProcessing() throws { @@ -530,7 +530,7 @@ class RegexDSLTests: XCTestCase { } // Assert the inferred capture type. - let _: (Substring, Substring).Type = type(of: unicodeData).Output.self + let _: (Substring, Substring).Type = type(of: unicodeData).RegexOutput.self let unicodeLine = "1BCA0..1BCA3 ; Control # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP" @@ -565,7 +565,7 @@ class RegexDSLTests: XCTestCase { typealias ExpectedMatch = ( Substring, Unicode.Scalar?, Unicode.Scalar??, Substring ) - let _: ExpectedMatch.Type = type(of: regexWithCapture).Output.self + let _: ExpectedMatch.Type = type(of: regexWithCapture).RegexOutput.self let maybeMatchResult = line.wholeMatch(of: regexWithCapture) let matchResult = try XCTUnwrap(maybeMatchResult) let (wholeMatch, lower, upper, propertyString) = matchResult.output @@ -600,7 +600,7 @@ class RegexDSLTests: XCTestCase { typealias ExpectedMatch = ( Substring, Unicode.Scalar, Unicode.Scalar?, Substring ) - let _: ExpectedMatch.Type = type(of: regexWithTryCapture).Output.self + let _: ExpectedMatch.Type = type(of: regexWithTryCapture).RegexOutput.self let maybeMatchResult = line.wholeMatch(of: regexWithTryCapture) let matchResult = try XCTUnwrap(maybeMatchResult) let (wholeMatch, lower, upper, propertyString) = matchResult.output @@ -744,7 +744,7 @@ class RegexDSLTests: XCTestCase { var dev: String? } struct SemanticVersionParser: CustomRegexComponent { - typealias Output = SemanticVersion + typealias RegexOutput = SemanticVersion func match( _ input: String, startingAt index: String.Index, From b3b8fee8a3ba5a27eadf7288efb84b8d7b91033c Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Thu, 14 Apr 2022 23:35:34 -0700 Subject: [PATCH 070/133] Add remaining availability annotations. Tests now have flag `-disable-availability-checking` because XCTests always test the just-built modules, rather than the modules in the OS. --- Package.swift | 40 +- Sources/RegexBuilder/Anchor.swift | 2 + Sources/RegexBuilder/CharacterClass.swift | 7 + Sources/RegexBuilder/DSL.swift | 10 + Sources/RegexBuilder/Match.swift | 1 + Sources/RegexBuilder/Variadics.swift | 711 ++++++++++++++++++ .../VariadicsGenerator.swift | 48 +- .../Algorithms/Algorithms/Contains.swift | 5 +- .../Algorithms/Algorithms/FirstRange.swift | 3 +- .../Algorithms/Algorithms/Ranges.swift | 4 +- .../Algorithms/Algorithms/Split.swift | 1 + .../Algorithms/Algorithms/StartsWith.swift | 2 +- .../Algorithms/Algorithms/Trim.swift | 19 +- .../Algorithms/Consumers/RegexConsumer.swift | 6 + .../Algorithms/Matching/FirstMatch.swift | 5 +- .../Algorithms/Matching/MatchReplace.swift | 7 +- .../Algorithms/Matching/Matches.swift | 3 + Sources/_StringProcessing/Executor.swift | 2 + .../Regex/AnyRegexOutput.swift | 8 + Sources/_StringProcessing/Regex/Core.swift | 3 +- .../Regex/DSLConsumers.swift | 1 + Sources/_StringProcessing/Regex/DSLTree.swift | 6 - Sources/_StringProcessing/Regex/Match.swift | 8 + Sources/_StringProcessing/Regex/Options.swift | 5 + .../_CharacterClassModel.swift | 16 +- 25 files changed, 873 insertions(+), 50 deletions(-) diff --git a/Package.swift b/Package.swift index 01c6adcb1..26b7f90af 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,7 @@ let availabilityDefinition = PackageDescription.SwiftSetting.unsafeFlags([ "-Xfrontend", "-define-availability", "-Xfrontend", - #""SwiftStdlib 5.7:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999""# + #"SwiftStdlib 5.7:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999"#, ]) let package = Package( @@ -66,44 +66,50 @@ let package = Package( .testTarget( name: "RegexTests", dependencies: ["_StringProcessing"], - swiftSettings: [availabilityDefinition]), + swiftSettings: [ + .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) + ]), .testTarget( name: "RegexBuilderTests", dependencies: ["_StringProcessing", "RegexBuilder"], swiftSettings: [ .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), - availabilityDefinition + .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) ]), .target( name: "Prototypes", dependencies: ["_RegexParser", "_StringProcessing"], - swiftSettings: [availabilityDefinition]), + swiftSettings: [ + .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) + ]), // MARK: Scripts .executableTarget( name: "VariadicsGenerator", dependencies: [ - .product(name: "ArgumentParser", package: "swift-argument-parser") + .product(name: "ArgumentParser", package: "swift-argument-parser") ]), .executableTarget( name: "PatternConverter", dependencies: [ - .product(name: "ArgumentParser", package: "swift-argument-parser"), - "_RegexParser", - "_StringProcessing" + .product(name: "ArgumentParser", package: "swift-argument-parser"), + "_RegexParser", + "_StringProcessing" ]), // MARK: Exercises .target( - name: "Exercises", - dependencies: ["_RegexParser", "Prototypes", "_StringProcessing", "RegexBuilder"], - swiftSettings: [ - .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), - availabilityDefinition - ]), + name: "Exercises", + dependencies: ["_RegexParser", "Prototypes", "_StringProcessing", "RegexBuilder"], + swiftSettings: [ + .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), + .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) + ]), .testTarget( - name: "ExercisesTests", - dependencies: ["Exercises"], - swiftSettings: [availabilityDefinition]), + name: "ExercisesTests", + dependencies: ["Exercises"], + swiftSettings: [ + .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) + ]) ] ) diff --git a/Sources/RegexBuilder/Anchor.swift b/Sources/RegexBuilder/Anchor.swift index 50129b94d..55b554aea 100644 --- a/Sources/RegexBuilder/Anchor.swift +++ b/Sources/RegexBuilder/Anchor.swift @@ -29,6 +29,7 @@ public struct Anchor { var isInverted: Bool = false } +@available(SwiftStdlib 5.7, *) extension Anchor: RegexComponent { var astAssertion: AST.Atom.AssertionKind { if !isInverted { @@ -63,6 +64,7 @@ extension Anchor: RegexComponent { // MARK: - Public API +@available(SwiftStdlib 5.7, *) extension Anchor { public static var startOfSubject: Anchor { Anchor(kind: .startOfSubject) diff --git a/Sources/RegexBuilder/CharacterClass.swift b/Sources/RegexBuilder/CharacterClass.swift index 99e981d33..d163c336b 100644 --- a/Sources/RegexBuilder/CharacterClass.swift +++ b/Sources/RegexBuilder/CharacterClass.swift @@ -37,18 +37,21 @@ public struct CharacterClass { } } +@available(SwiftStdlib 5.7, *) extension CharacterClass: RegexComponent { public var regex: Regex { return Regex(node: DSLTree.Node.customCharacterClass(ccc)) } } +@available(SwiftStdlib 5.7, *) extension CharacterClass { public var inverted: CharacterClass { CharacterClass(ccc.inverted) } } +@available(SwiftStdlib 5.7, *) extension RegexComponent where Self == CharacterClass { public static var any: CharacterClass { .init(DSLTree.CustomCharacterClass(members: [.atom(.any)])) @@ -91,6 +94,7 @@ extension RegexComponent where Self == CharacterClass { } } +@available(SwiftStdlib 5.7, *) extension RegexComponent where Self == CharacterClass { /// Returns a character class that matches any character in the given string /// or sequence. @@ -112,6 +116,7 @@ extension RegexComponent where Self == CharacterClass { } // Unicode properties +@available(SwiftStdlib 5.7, *) extension CharacterClass { public static func generalCategory(_ category: Unicode.GeneralCategory) -> CharacterClass { guard let extendedCategory = category.extendedGeneralCategory else { @@ -179,6 +184,7 @@ extension Unicode.GeneralCategory { // MARK: - Set algebra methods +@available(SwiftStdlib 5.7, *) extension RegexComponent where Self == CharacterClass { public init(_ first: CharacterClass, _ rest: CharacterClass...) { if rest.isEmpty { @@ -191,6 +197,7 @@ extension RegexComponent where Self == CharacterClass { } } +@available(SwiftStdlib 5.7, *) extension CharacterClass { public func union(_ other: CharacterClass) -> CharacterClass { CharacterClass(.init(members: [ diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 39a62984f..3c5f5ab5f 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -12,6 +12,7 @@ import _RegexParser @_spi(RegexBuilder) import _StringProcessing +@available(SwiftStdlib 5.7, *) extension Regex { public init( @RegexComponentBuilder _ content: () -> Content @@ -22,10 +23,12 @@ extension Regex { // A convenience protocol for builtin regex components that are initialized with // a `DSLTree` node. +@available(SwiftStdlib 5.7, *) internal protocol _BuiltinRegexComponent: RegexComponent { init(_ regex: Regex) } +@available(SwiftStdlib 5.7, *) extension _BuiltinRegexComponent { init(node: DSLTree.Node) { self.init(Regex(node: node)) @@ -34,6 +37,7 @@ extension _BuiltinRegexComponent { // MARK: - Primitive regex components +@available(SwiftStdlib 5.7, *) extension String: RegexComponent { public typealias Output = Substring @@ -42,6 +46,7 @@ extension String: RegexComponent { } } +@available(SwiftStdlib 5.7, *) extension Substring: RegexComponent { public typealias Output = Substring @@ -50,6 +55,7 @@ extension Substring: RegexComponent { } } +@available(SwiftStdlib 5.7, *) extension Character: RegexComponent { public typealias Output = Substring @@ -58,6 +64,7 @@ extension Character: RegexComponent { } } +@available(SwiftStdlib 5.7, *) extension UnicodeScalar: RegexComponent { public typealias Output = Substring @@ -110,6 +117,7 @@ public struct QuantificationBehavior { extension DSLTree.Node { /// Generates a DSLTree node for a repeated range of the given DSLTree node. /// Individual public API functions are in the generated Variadics.swift file. + @available(SwiftStdlib 5.7, *) static func repeating( _ range: Range, _ behavior: QuantificationBehavior, @@ -137,6 +145,7 @@ extension DSLTree.Node { } } +@available(SwiftStdlib 5.7, *) extension QuantificationBehavior { /// Match as much of the input string as possible, backtracking when /// necessary. @@ -304,6 +313,7 @@ public struct Reference: RegexComponent { } } +@available(SwiftStdlib 5.7, *) extension Regex.Match { public subscript(_ reference: Reference) -> Capture { self[reference.id] diff --git a/Sources/RegexBuilder/Match.swift b/Sources/RegexBuilder/Match.swift index 1b4b3951b..78a466a18 100644 --- a/Sources/RegexBuilder/Match.swift +++ b/Sources/RegexBuilder/Match.swift @@ -11,6 +11,7 @@ import _StringProcessing +@available(SwiftStdlib 5.7, *) extension String { @available(SwiftStdlib 5.7, *) public func wholeMatch( diff --git a/Sources/RegexBuilder/Variadics.swift b/Sources/RegexBuilder/Variadics.swift index e7bf02237..2ac5b3231 100644 --- a/Sources/RegexBuilder/Variadics.swift +++ b/Sources/RegexBuilder/Variadics.swift @@ -14,462 +14,594 @@ import _RegexParser @_spi(RegexBuilder) import _StringProcessing +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.RegexOutput == (W1, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex where R0.RegexOutput == W0 { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0)> where R0.RegexOutput == (W0, C0) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1)> where R0.RegexOutput == (W0, C0, C1) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == (W0, C0, C1, C2) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0, C1, C2, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { @@ -478,7 +610,9 @@ extension RegexComponentBuilder { } +@available(SwiftStdlib 5.7, *) extension Optionally { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: Component, @@ -488,7 +622,9 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension Optionally { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ behavior: QuantificationBehavior = .eagerly, @@ -498,14 +634,18 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildLimitedAvailability( _ component: Component ) -> Regex { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: Component, @@ -515,7 +655,9 @@ extension ZeroOrMore { } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ behavior: QuantificationBehavior = .eagerly, @@ -526,7 +668,9 @@ extension ZeroOrMore { } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: Component, @@ -536,7 +680,9 @@ extension OneOrMore { } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ behavior: QuantificationBehavior = .eagerly, @@ -547,7 +693,9 @@ extension OneOrMore { } +@available(SwiftStdlib 5.7, *) extension Repeat { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: Component, @@ -558,6 +706,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) } + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( count: Int, @@ -568,6 +717,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) } + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: Component, @@ -577,6 +727,7 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, @@ -586,7 +737,9 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -595,7 +748,9 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension Optionally { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -604,14 +759,18 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?)> where Component.RegexOutput == (W, C0) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -620,7 +779,9 @@ extension ZeroOrMore { } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -630,7 +791,9 @@ extension ZeroOrMore { } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -639,7 +802,9 @@ extension OneOrMore { } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -649,7 +814,9 @@ extension OneOrMore { } +@available(SwiftStdlib 5.7, *) extension Repeat { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, count: Int @@ -659,6 +826,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( count: Int, @RegexComponentBuilder _ component: () -> Component @@ -668,6 +836,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, @@ -676,6 +845,7 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, _ behavior: QuantificationBehavior = .eagerly, @@ -684,7 +854,9 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -693,7 +865,9 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension Optionally { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -702,14 +876,18 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?)> where Component.RegexOutput == (W, C0, C1) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -718,7 +896,9 @@ extension ZeroOrMore { } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -728,7 +908,9 @@ extension ZeroOrMore { } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -737,7 +919,9 @@ extension OneOrMore { } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -747,7 +931,9 @@ extension OneOrMore { } +@available(SwiftStdlib 5.7, *) extension Repeat { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, count: Int @@ -757,6 +943,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( count: Int, @RegexComponentBuilder _ component: () -> Component @@ -766,6 +953,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, @@ -774,6 +962,7 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, _ behavior: QuantificationBehavior = .eagerly, @@ -782,7 +971,9 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -791,7 +982,9 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension Optionally { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -800,14 +993,18 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?)> where Component.RegexOutput == (W, C0, C1, C2) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -816,7 +1013,9 @@ extension ZeroOrMore { } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -826,7 +1025,9 @@ extension ZeroOrMore { } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -835,7 +1036,9 @@ extension OneOrMore { } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -845,7 +1048,9 @@ extension OneOrMore { } +@available(SwiftStdlib 5.7, *) extension Repeat { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, count: Int @@ -855,6 +1060,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( count: Int, @RegexComponentBuilder _ component: () -> Component @@ -864,6 +1070,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, @@ -872,6 +1079,7 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, _ behavior: QuantificationBehavior = .eagerly, @@ -880,7 +1088,9 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -889,7 +1099,9 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension Optionally { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -898,14 +1110,18 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.RegexOutput == (W, C0, C1, C2, C3) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -914,7 +1130,9 @@ extension ZeroOrMore { } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -924,7 +1142,9 @@ extension ZeroOrMore { } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -933,7 +1153,9 @@ extension OneOrMore { } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -943,7 +1165,9 @@ extension OneOrMore { } +@available(SwiftStdlib 5.7, *) extension Repeat { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, count: Int @@ -953,6 +1177,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( count: Int, @RegexComponentBuilder _ component: () -> Component @@ -962,6 +1187,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, @@ -970,6 +1196,7 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, _ behavior: QuantificationBehavior = .eagerly, @@ -978,7 +1205,9 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -987,7 +1216,9 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension Optionally { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -996,14 +1227,18 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1012,7 +1247,9 @@ extension ZeroOrMore { } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1022,7 +1259,9 @@ extension ZeroOrMore { } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1031,7 +1270,9 @@ extension OneOrMore { } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1041,7 +1282,9 @@ extension OneOrMore { } +@available(SwiftStdlib 5.7, *) extension Repeat { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, count: Int @@ -1051,6 +1294,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( count: Int, @RegexComponentBuilder _ component: () -> Component @@ -1060,6 +1304,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, @@ -1068,6 +1313,7 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, _ behavior: QuantificationBehavior = .eagerly, @@ -1076,7 +1322,9 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1085,7 +1333,9 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension Optionally { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1094,14 +1344,18 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1110,7 +1364,9 @@ extension ZeroOrMore { } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1120,7 +1376,9 @@ extension ZeroOrMore { } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1129,7 +1387,9 @@ extension OneOrMore { } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1139,7 +1399,9 @@ extension OneOrMore { } +@available(SwiftStdlib 5.7, *) extension Repeat { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, count: Int @@ -1149,6 +1411,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( count: Int, @RegexComponentBuilder _ component: () -> Component @@ -1158,6 +1421,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, @@ -1166,6 +1430,7 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, _ behavior: QuantificationBehavior = .eagerly, @@ -1174,7 +1439,9 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1183,7 +1450,9 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension Optionally { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1192,14 +1461,18 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1208,7 +1481,9 @@ extension ZeroOrMore { } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1218,7 +1493,9 @@ extension ZeroOrMore { } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1227,7 +1504,9 @@ extension OneOrMore { } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1237,7 +1516,9 @@ extension OneOrMore { } +@available(SwiftStdlib 5.7, *) extension Repeat { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, count: Int @@ -1247,6 +1528,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( count: Int, @RegexComponentBuilder _ component: () -> Component @@ -1256,6 +1538,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, @@ -1264,6 +1547,7 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, _ behavior: QuantificationBehavior = .eagerly, @@ -1272,7 +1556,9 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1281,7 +1567,9 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension Optionally { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1290,14 +1578,18 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1306,7 +1598,9 @@ extension ZeroOrMore { } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1316,7 +1610,9 @@ extension ZeroOrMore { } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1325,7 +1621,9 @@ extension OneOrMore { } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1335,7 +1633,9 @@ extension OneOrMore { } +@available(SwiftStdlib 5.7, *) extension Repeat { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, count: Int @@ -1345,6 +1645,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( count: Int, @RegexComponentBuilder _ component: () -> Component @@ -1354,6 +1655,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, @@ -1362,6 +1664,7 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, _ behavior: QuantificationBehavior = .eagerly, @@ -1370,7 +1673,9 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1379,7 +1684,9 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension Optionally { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1388,14 +1695,18 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1404,7 +1715,9 @@ extension ZeroOrMore { } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1414,7 +1727,9 @@ extension ZeroOrMore { } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1423,7 +1738,9 @@ extension OneOrMore { } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1433,7 +1750,9 @@ extension OneOrMore { } +@available(SwiftStdlib 5.7, *) extension Repeat { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, count: Int @@ -1443,6 +1762,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( count: Int, @RegexComponentBuilder _ component: () -> Component @@ -1452,6 +1772,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, @@ -1460,6 +1781,7 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, _ behavior: QuantificationBehavior = .eagerly, @@ -1468,7 +1790,9 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1477,7 +1801,9 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension Optionally { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1486,14 +1812,18 @@ extension Optionally { } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1502,7 +1832,9 @@ extension ZeroOrMore { } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1512,7 +1844,9 @@ extension ZeroOrMore { } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ behavior: QuantificationBehavior = .eagerly @@ -1521,7 +1855,9 @@ extension OneOrMore { } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { + @available(SwiftStdlib 5.7, *) public init( _ behavior: QuantificationBehavior = .eagerly, @RegexComponentBuilder _ component: () -> Component @@ -1531,7 +1867,9 @@ extension OneOrMore { } +@available(SwiftStdlib 5.7, *) extension Repeat { + @available(SwiftStdlib 5.7, *) public init( _ component: Component, count: Int @@ -1541,6 +1879,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( count: Int, @RegexComponentBuilder _ component: () -> Component @@ -1550,6 +1889,7 @@ extension Repeat { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, @@ -1558,6 +1898,7 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, _ behavior: QuantificationBehavior = .eagerly, @@ -1566,7 +1907,9 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component @@ -1575,7 +1918,9 @@ extension Local { } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> Component @@ -1583,7 +1928,9 @@ extension Local { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( _ component: Component ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { @@ -1591,14 +1938,18 @@ extension Local { } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( _ component: Component ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { @@ -1606,14 +1957,18 @@ extension Local { } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( _ component: Component ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { @@ -1621,14 +1976,18 @@ extension Local { } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( _ component: Component ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { @@ -1636,14 +1995,18 @@ extension Local { } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( _ component: Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { @@ -1651,14 +2014,18 @@ extension Local { } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( _ component: Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { @@ -1666,14 +2033,18 @@ extension Local { } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( _ component: Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { @@ -1681,14 +2052,18 @@ extension Local { } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( _ component: Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { @@ -1696,14 +2071,18 @@ extension Local { } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( _ component: Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { @@ -1711,14 +2090,18 @@ extension Local { } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( _ component: Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { @@ -1726,521 +2109,675 @@ extension Local { } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf where R0: RegexComponent, R1: RegexComponent { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.RegexOutput == (W1, C9) { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?)> where R: RegexComponent, R.RegexOutput == (W, C0) { .init(node: .orderedChoice([regex.regex.root])) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1) { .init(node: .orderedChoice([regex.regex.root])) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2) { .init(node: .orderedChoice([regex.regex.root])) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3) { .init(node: .orderedChoice([regex.regex.root])) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4) { .init(node: .orderedChoice([regex.regex.root])) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { .init(node: .orderedChoice([regex.regex.root])) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { .init(node: .orderedChoice([regex.regex.root])) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: .orderedChoice([regex.regex.root])) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: .orderedChoice([regex.regex.root])) } } +@available(SwiftStdlib 5.7, *) extension AlternationBuilder { + @available(SwiftStdlib 5.7, *) public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: .orderedChoice([regex.regex.root])) } } // MARK: - Non-builder capture arity 0 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: R @@ -2248,6 +2785,7 @@ extension Capture { self.init(node: .capture(component.regex.root)) } + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: R, as reference: Reference @@ -2255,6 +2793,7 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: R, @@ -2267,6 +2806,7 @@ extension Capture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: R, @@ -2283,7 +2823,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: R, @@ -2296,6 +2838,7 @@ extension TryCapture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: R, @@ -2314,7 +2857,9 @@ extension TryCapture { // MARK: - Builder capture arity 0 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> R @@ -2322,6 +2867,7 @@ extension Capture { self.init(node: .capture(component().regex.root)) } + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( as reference: Reference, @@ -2332,6 +2878,7 @@ extension Capture { component().regex.root)) } + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> R, @@ -2344,6 +2891,7 @@ extension Capture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( as reference: Reference, @@ -2360,7 +2908,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> R, @@ -2373,6 +2923,7 @@ extension TryCapture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( as reference: Reference, @@ -2391,19 +2942,23 @@ extension TryCapture { // MARK: - Non-builder capture arity 1 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( _ component: R ) where RegexOutput == (Substring, W, C0), R.RegexOutput == (W, C0) { self.init(node: .capture(component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference ) where RegexOutput == (Substring, W, C0), R.RegexOutput == (W, C0) { self.init(node: .capture(reference: reference.id, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -2415,6 +2970,7 @@ extension Capture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -2430,7 +2986,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? @@ -2442,6 +3000,7 @@ extension TryCapture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -2459,13 +3018,16 @@ extension TryCapture { // MARK: - Builder capture arity 1 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R ) where RegexOutput == (Substring, W, C0), R.RegexOutput == (W, C0) { self.init(node: .capture(component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R @@ -2475,6 +3037,7 @@ extension Capture { component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -2486,6 +3049,7 @@ extension Capture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -2501,7 +3065,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? @@ -2513,6 +3079,7 @@ extension TryCapture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -2530,19 +3097,23 @@ extension TryCapture { // MARK: - Non-builder capture arity 2 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( _ component: R ) where RegexOutput == (Substring, W, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture(component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference ) where RegexOutput == (Substring, W, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture(reference: reference.id, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -2554,6 +3125,7 @@ extension Capture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -2569,7 +3141,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? @@ -2581,6 +3155,7 @@ extension TryCapture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -2598,13 +3173,16 @@ extension TryCapture { // MARK: - Builder capture arity 2 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R ) where RegexOutput == (Substring, W, C0, C1), R.RegexOutput == (W, C0, C1) { self.init(node: .capture(component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R @@ -2614,6 +3192,7 @@ extension Capture { component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -2625,6 +3204,7 @@ extension Capture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -2640,7 +3220,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? @@ -2652,6 +3234,7 @@ extension TryCapture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -2669,19 +3252,23 @@ extension TryCapture { // MARK: - Non-builder capture arity 3 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( _ component: R ) where RegexOutput == (Substring, W, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture(component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference ) where RegexOutput == (Substring, W, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture(reference: reference.id, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -2693,6 +3280,7 @@ extension Capture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -2708,7 +3296,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? @@ -2720,6 +3310,7 @@ extension TryCapture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -2737,13 +3328,16 @@ extension TryCapture { // MARK: - Builder capture arity 3 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R ) where RegexOutput == (Substring, W, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { self.init(node: .capture(component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R @@ -2753,6 +3347,7 @@ extension Capture { component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -2764,6 +3359,7 @@ extension Capture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -2779,7 +3375,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? @@ -2791,6 +3389,7 @@ extension TryCapture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -2808,19 +3407,23 @@ extension TryCapture { // MARK: - Non-builder capture arity 4 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( _ component: R ) where RegexOutput == (Substring, W, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture(component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference ) where RegexOutput == (Substring, W, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture(reference: reference.id, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -2832,6 +3435,7 @@ extension Capture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -2847,7 +3451,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? @@ -2859,6 +3465,7 @@ extension TryCapture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -2876,13 +3483,16 @@ extension TryCapture { // MARK: - Builder capture arity 4 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R ) where RegexOutput == (Substring, W, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { self.init(node: .capture(component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R @@ -2892,6 +3502,7 @@ extension Capture { component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -2903,6 +3514,7 @@ extension Capture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -2918,7 +3530,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? @@ -2930,6 +3544,7 @@ extension TryCapture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -2947,19 +3562,23 @@ extension TryCapture { // MARK: - Non-builder capture arity 5 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( _ component: R ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture(component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture(reference: reference.id, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -2971,6 +3590,7 @@ extension Capture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -2986,7 +3606,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? @@ -2998,6 +3620,7 @@ extension TryCapture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -3015,13 +3638,16 @@ extension TryCapture { // MARK: - Builder capture arity 5 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { self.init(node: .capture(component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R @@ -3031,6 +3657,7 @@ extension Capture { component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -3042,6 +3669,7 @@ extension Capture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -3057,7 +3685,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? @@ -3069,6 +3699,7 @@ extension TryCapture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -3086,19 +3717,23 @@ extension TryCapture { // MARK: - Non-builder capture arity 6 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( _ component: R ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture(component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture(reference: reference.id, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -3110,6 +3745,7 @@ extension Capture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -3125,7 +3761,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? @@ -3137,6 +3775,7 @@ extension TryCapture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -3154,13 +3793,16 @@ extension TryCapture { // MARK: - Builder capture arity 6 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { self.init(node: .capture(component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R @@ -3170,6 +3812,7 @@ extension Capture { component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -3181,6 +3824,7 @@ extension Capture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -3196,7 +3840,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? @@ -3208,6 +3854,7 @@ extension TryCapture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -3225,19 +3872,23 @@ extension TryCapture { // MARK: - Non-builder capture arity 7 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( _ component: R ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(reference: reference.id, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -3249,6 +3900,7 @@ extension Capture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -3264,7 +3916,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? @@ -3276,6 +3930,7 @@ extension TryCapture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -3293,13 +3948,16 @@ extension TryCapture { // MARK: - Builder capture arity 7 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R @@ -3309,6 +3967,7 @@ extension Capture { component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -3320,6 +3979,7 @@ extension Capture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -3335,7 +3995,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? @@ -3347,6 +4009,7 @@ extension TryCapture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -3364,19 +4027,23 @@ extension TryCapture { // MARK: - Non-builder capture arity 8 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( _ component: R ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(reference: reference.id, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -3388,6 +4055,7 @@ extension Capture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -3403,7 +4071,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? @@ -3415,6 +4085,7 @@ extension TryCapture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -3432,13 +4103,16 @@ extension TryCapture { // MARK: - Builder capture arity 8 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R @@ -3448,6 +4122,7 @@ extension Capture { component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -3459,6 +4134,7 @@ extension Capture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -3474,7 +4150,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? @@ -3486,6 +4164,7 @@ extension TryCapture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -3503,19 +4182,23 @@ extension TryCapture { // MARK: - Non-builder capture arity 9 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( _ component: R ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(reference: reference.id, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -3527,6 +4210,7 @@ extension Capture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -3542,7 +4226,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? @@ -3554,6 +4240,7 @@ extension TryCapture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -3571,13 +4258,16 @@ extension TryCapture { // MARK: - Builder capture arity 9 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R @@ -3587,6 +4277,7 @@ extension Capture { component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -3598,6 +4289,7 @@ extension Capture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -3613,7 +4305,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? @@ -3625,6 +4319,7 @@ extension TryCapture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -3642,19 +4337,23 @@ extension TryCapture { // MARK: - Non-builder capture arity 10 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( _ component: R ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(reference: reference.id, component.regex.root)) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -3666,6 +4365,7 @@ extension Capture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -3681,7 +4381,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? @@ -3693,6 +4395,7 @@ extension TryCapture { component.regex.root))) } + @available(SwiftStdlib 5.7, *) public init( _ component: R, as reference: Reference, @@ -3710,13 +4413,16 @@ extension TryCapture { // MARK: - Builder capture arity 10 +@available(SwiftStdlib 5.7, *) extension Capture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R @@ -3726,6 +4432,7 @@ extension Capture { component().regex.root)) } + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -3737,6 +4444,7 @@ extension Capture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, @@ -3752,7 +4460,9 @@ extension Capture { } } +@available(SwiftStdlib 5.7, *) extension TryCapture { + @available(SwiftStdlib 5.7, *) public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? @@ -3764,6 +4474,7 @@ extension TryCapture { component().regex.root))) } + @available(SwiftStdlib 5.7, *) public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index 1a0742f20..2df2f7c96 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -96,6 +96,7 @@ let regexTypeName = "Regex" let baseMatchTypeName = "Substring" let concatBuilderName = "RegexComponentBuilder" let altBuilderName = "AlternationBuilder" +let defaultAvailableAttr = "@available(SwiftStdlib 5.7, *)" @main struct VariadicsGenerator: ParsableCommand { @@ -240,8 +241,10 @@ struct VariadicsGenerator: ParsableCommand { }() // Emit concatenation builder. - output("extension \(concatBuilderName) {\n") output(""" + \(defaultAvailableAttr) + extension \(concatBuilderName) { + \(defaultAvailableAttr) public static func buildPartialBlock<\(genericParams)>( accumulated: R0, next: R1 ) -> \(regexTypeName)<\(matchType)> \(whereClause) { @@ -255,9 +258,11 @@ struct VariadicsGenerator: ParsableCommand { func emitConcatenationWithEmpty(leftArity: Int) { // T + () = T output(""" - extension \(concatBuilderName) { - public static func buildPartialBlock= 0) let params = QuantifierParameters(kind: kind, arity: arity) output(""" + \(defaultAvailableAttr) extension \(kind.rawValue) { + \(defaultAvailableAttr) \(params.disfavored)\ public init<\(params.genericParams)>( _ component: Component, @@ -377,7 +384,9 @@ struct VariadicsGenerator: ParsableCommand { } } + \(defaultAvailableAttr) extension \(kind.rawValue) { + \(defaultAvailableAttr) \(params.disfavored)\ public init<\(params.genericParams)>( _ behavior: QuantificationBehavior = .eagerly, @@ -389,7 +398,9 @@ struct VariadicsGenerator: ParsableCommand { \(kind == .zeroOrOne ? """ + \(defaultAvailableAttr) extension \(concatBuilderName) { + \(defaultAvailableAttr) public static func buildLimitedAvailability<\(params.genericParams)>( _ component: Component ) -> \(regexTypeName)<\(params.matchType)> \(params.whereClause) { @@ -433,7 +444,9 @@ struct VariadicsGenerator: ParsableCommand { (arity == 0 ? "" : ", Component.\(outputAssociatedTypeName) == (W, \(capturesJoined))") output(""" + \(defaultAvailableAttr) extension \(groupName) { + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams)>( _ component: Component @@ -442,7 +455,9 @@ struct VariadicsGenerator: ParsableCommand { } } + \(defaultAvailableAttr) extension \(groupName) { + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams)>( @\(concatBuilderName) _ component: () -> Component @@ -463,7 +478,9 @@ struct VariadicsGenerator: ParsableCommand { // We would need to prohibit `repeat(count: 0)`; can only happen at runtime output(""" + \(defaultAvailableAttr) extension Repeat { + \(defaultAvailableAttr) \(params.disfavored)\ public init<\(params.genericParams)>( _ component: Component, @@ -474,6 +491,7 @@ struct VariadicsGenerator: ParsableCommand { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) } + \(defaultAvailableAttr) \(params.disfavored)\ public init<\(params.genericParams)>( count: Int, @@ -484,6 +502,7 @@ struct VariadicsGenerator: ParsableCommand { self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) } + \(defaultAvailableAttr) \(params.disfavored)\ public init<\(params.genericParams), R: RangeExpression>( _ component: Component, @@ -493,6 +512,7 @@ struct VariadicsGenerator: ParsableCommand { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, @@ -545,7 +565,9 @@ struct VariadicsGenerator: ParsableCommand { return "(\(baseMatchTypeName), \(resultCaptures))" }() output(""" + \(defaultAvailableAttr) extension \(altBuilderName) { + \(defaultAvailableAttr) public static func buildPartialBlock<\(genericParams)>( accumulated: R0, next: R1 ) -> ChoiceOf<\(matchType)> \(whereClause) { @@ -571,7 +593,9 @@ struct VariadicsGenerator: ParsableCommand { """ let resultCaptures = (0..(first regex: R) -> ChoiceOf<(W, \(resultCaptures))> \(whereClause) { .init(node: .orderedChoice([regex.regex.root])) } @@ -600,7 +624,9 @@ struct VariadicsGenerator: ParsableCommand { output(""" // MARK: - Non-builder capture arity \(arity) + \(defaultAvailableAttr) extension Capture { + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams)>( _ component: R @@ -608,6 +634,7 @@ struct VariadicsGenerator: ParsableCommand { self.init(node: .capture(component.regex.root)) } + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams)>( _ component: R, as reference: Reference @@ -615,6 +642,7 @@ struct VariadicsGenerator: ParsableCommand { self.init(node: .capture(reference: reference.id, component.regex.root)) } + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, @@ -627,6 +655,7 @@ struct VariadicsGenerator: ParsableCommand { component.regex.root))) } + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, @@ -643,7 +672,9 @@ struct VariadicsGenerator: ParsableCommand { } } + \(defaultAvailableAttr) extension TryCapture { + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, @@ -656,6 +687,7 @@ struct VariadicsGenerator: ParsableCommand { component.regex.root))) } + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, @@ -674,7 +706,9 @@ struct VariadicsGenerator: ParsableCommand { // MARK: - Builder capture arity \(arity) + \(defaultAvailableAttr) extension Capture { + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams)>( @\(concatBuilderName) _ component: () -> R @@ -682,6 +716,7 @@ struct VariadicsGenerator: ParsableCommand { self.init(node: .capture(component().regex.root)) } + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams)>( as reference: Reference, @@ -692,6 +727,7 @@ struct VariadicsGenerator: ParsableCommand { component().regex.root)) } + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams), NewCapture>( @\(concatBuilderName) _ component: () -> R, @@ -704,6 +740,7 @@ struct VariadicsGenerator: ParsableCommand { component().regex.root))) } + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams), NewCapture>( as reference: Reference, @@ -720,7 +757,9 @@ struct VariadicsGenerator: ParsableCommand { } } + \(defaultAvailableAttr) extension TryCapture { + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams), NewCapture>( @\(concatBuilderName) _ component: () -> R, @@ -733,6 +772,7 @@ struct VariadicsGenerator: ParsableCommand { component().regex.root))) } + \(defaultAvailableAttr) \(disfavored)\ public init<\(genericParams), NewCapture>( as reference: Reference, diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift index 2f38095d8..1d4332ad0 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift @@ -39,7 +39,10 @@ extension BidirectionalCollection where Element: Comparable { func contains(_ other: S) -> Bool where S.Element == Element { - firstRange(of: other) != nil + if #available(SwiftStdlib 5.7, *) { + return firstRange(of: other) != nil + } + fatalError() } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift index e75cdbdc4..508c04663 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift @@ -77,7 +77,8 @@ extension BidirectionalCollection where SubSequence == Substring { public func firstRange(of regex: R) -> Range? { firstRange(of: RegexConsumer(regex)) } - + + @available(SwiftStdlib 5.7, *) func lastRange(of regex: R) -> Range? { lastRange(of: RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift index 3a45b86a2..f1861fcf2 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift @@ -218,12 +218,14 @@ extension BidirectionalCollection where Element: Comparable { extension BidirectionalCollection where SubSequence == Substring { // FIXME: Replace `RangesCollection` when SE-0346 is enabled + @available(SwiftStdlib 5.7, *) func ranges( of regex: R ) -> RangesCollection> { ranges(of: RegexConsumer(regex)) } - + + @available(SwiftStdlib 5.7, *) func rangesFromBack( of regex: R ) -> ReversedRangesCollection> { diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift index 898f93048..485bc3b7f 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -280,6 +280,7 @@ extension BidirectionalCollection where Element: Comparable { // MARK: Regex algorithms +@available(SwiftStdlib 5.7, *) extension BidirectionalCollection where SubSequence == Substring { // FIXME: Replace `SplitCollection` when SE-0346 is enabled /// Returns the longest possible subsequences of the collection, in order, diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift index 01572fe49..0dd91f360 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift @@ -47,13 +47,13 @@ extension BidirectionalCollection where Element: Equatable { // MARK: Regex algorithms +@available(SwiftStdlib 5.7, *) extension BidirectionalCollection where SubSequence == Substring { /// Returns a Boolean value indicating whether the initial elements of the /// sequence are the same as the elements in the specified regex. /// - Parameter regex: A regex to compare to this sequence. /// - Returns: `true` if the initial elements of the sequence matches the /// beginning of `regex`; otherwise, `false`. - @available(SwiftStdlib 5.7, *) public func starts(with regex: R) -> Bool { starts(with: RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift index fd0dbefdb..73a5cd554 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift @@ -288,11 +288,13 @@ extension BidirectionalCollection where SubSequence == Substring { public func trimmingPrefix(_ regex: R) -> SubSequence { trimmingPrefix(RegexConsumer(regex)) } - + + @available(SwiftStdlib 5.7, *) func trimmingSuffix(_ regex: R) -> SubSequence { trimmingSuffix(RegexConsumer(regex)) } - + + @available(SwiftStdlib 5.7, *) func trimming(_ regex: R) -> SubSequence { trimming(RegexConsumer(regex)) } @@ -307,11 +309,13 @@ extension RangeReplaceableCollection public mutating func trimPrefix(_ regex: R) { trimPrefix(RegexConsumer(regex)) } - + + @available(SwiftStdlib 5.7, *) mutating func trimSuffix(_ regex: R) { trimSuffix(RegexConsumer(regex)) } - + + @available(SwiftStdlib 5.7, *) mutating func trim(_ regex: R) { let consumer = RegexConsumer(regex) trimPrefix(consumer) @@ -320,14 +324,17 @@ extension RangeReplaceableCollection } extension Substring { + @available(SwiftStdlib 5.7, *) mutating func trimPrefix(_ regex: R) { trimPrefix(RegexConsumer(regex)) } - + + @available(SwiftStdlib 5.7, *) mutating func trimSuffix(_ regex: R) { trimSuffix(RegexConsumer(regex)) } - + + @available(SwiftStdlib 5.7, *) mutating func trim(_ regex: R) { let consumer = RegexConsumer(regex) trimPrefix(consumer) diff --git a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift index 81f3ebb3e..4956406da 100644 --- a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift +++ b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift @@ -10,6 +10,7 @@ //===----------------------------------------------------------------------===// // FIXME: What even is this? Can we delete this whole thing? +@available(SwiftStdlib 5.7, *) struct RegexConsumer< R: RegexComponent, Consumed: BidirectionalCollection > where Consumed.SubSequence == Substring { @@ -21,6 +22,7 @@ struct RegexConsumer< } } +@available(SwiftStdlib 5.7, *) extension RegexConsumer { func _matchingConsuming( _ consumed: Substring, in range: Range @@ -36,6 +38,7 @@ extension RegexConsumer { // TODO: Explicitly implement the non-matching consumer/searcher protocols as // well, taking advantage of the fact that the captures can be ignored +@available(SwiftStdlib 5.7, *) extension RegexConsumer: MatchingCollectionConsumer { typealias Match = R.RegexOutput @@ -47,6 +50,7 @@ extension RegexConsumer: MatchingCollectionConsumer { } // TODO: We'll want to bake backwards into the engine +@available(SwiftStdlib 5.7, *) extension RegexConsumer: BidirectionalMatchingCollectionConsumer { func matchingConsumingBack( _ consumed: Consumed, in range: Range @@ -67,6 +71,7 @@ extension RegexConsumer: BidirectionalMatchingCollectionConsumer { } } +@available(SwiftStdlib 5.7, *) extension RegexConsumer: MatchingStatelessCollectionSearcher { typealias Searched = Consumed @@ -81,6 +86,7 @@ extension RegexConsumer: MatchingStatelessCollectionSearcher { } // TODO: Bake in search-back to engine too +@available(SwiftStdlib 5.7, *) extension RegexConsumer: BackwardMatchingStatelessCollectionSearcher { typealias BackwardSearched = Consumed diff --git a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift index 093a47b71..a4dce19b7 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift @@ -38,12 +38,14 @@ extension BidirectionalCollection { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { + @available(SwiftStdlib 5.7, *) func firstMatch( of regex: R ) -> _MatchResult>? { firstMatch(of: RegexConsumer(regex)) } - + + @available(SwiftStdlib 5.7, *) func lastMatch( of regex: R ) -> _BackwardMatchResult>? { @@ -54,6 +56,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: The regex to search for. /// - Returns: The first match of `regex` in the collection, or `nil` if /// there isn't a match. + @available(SwiftStdlib 5.7, *) public func firstMatch( of r: R ) -> Regex.Match? { diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift index 461c08e02..8485182de 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift @@ -75,6 +75,7 @@ extension RangeReplaceableCollection { // MARK: Regex algorithms extension RangeReplaceableCollection where SubSequence == Substring { + @available(SwiftStdlib 5.7, *) func replacing( _ regex: R, with replacement: (_MatchResult>) throws -> Replacement, @@ -87,7 +88,8 @@ extension RangeReplaceableCollection where SubSequence == Substring { subrange: subrange, maxReplacements: maxReplacements) } - + + @available(SwiftStdlib 5.7, *) func replacing( _ regex: R, with replacement: (_MatchResult>) throws -> Replacement, @@ -99,7 +101,8 @@ extension RangeReplaceableCollection where SubSequence == Substring { subrange: startIndex..( _ regex: R, with replacement: (_MatchResult>) throws -> Replacement, diff --git a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift index 484737f05..6736e3033 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift @@ -188,12 +188,14 @@ extension BidirectionalCollection where SubSequence == Substring { /// Returns a collection containing all matches of the specified regex. /// - Parameter regex: The regex to search for. /// - Returns: A collection of matches of `regex`. + @available(SwiftStdlib 5.7, *) func matches( of regex: R ) -> MatchesCollection> { matches(of: RegexConsumer(regex)) } + @available(SwiftStdlib 5.7, *) func matchesFromBack( of regex: R ) -> ReversedMatchesCollection> { @@ -202,6 +204,7 @@ extension BidirectionalCollection where SubSequence == Substring { // FIXME: Replace the returned value as `some Collection.Match> // when SE-0346 is enabled + @available(SwiftStdlib 5.7, *) func _matches(of r: R) -> [Regex.Match] { let slice = self[...] var start = self.startIndex diff --git a/Sources/_StringProcessing/Executor.swift b/Sources/_StringProcessing/Executor.swift index 563e90970..d911c3512 100644 --- a/Sources/_StringProcessing/Executor.swift +++ b/Sources/_StringProcessing/Executor.swift @@ -19,6 +19,7 @@ struct Executor { self.engine = Engine(program, enableTracing: enablesTracing) } + @available(SwiftStdlib 5.7, *) func match( _ input: String, in inputRange: Range, @@ -64,6 +65,7 @@ struct Executor { value: value) } + @available(SwiftStdlib 5.7, *) func dynamicMatch( _ input: String, in inputRange: Range, diff --git a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift index ea9659faf..16829ff78 100644 --- a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift +++ b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift @@ -11,6 +11,7 @@ import _RegexParser +@available(SwiftStdlib 5.7, *) extension Regex where Output == AnyRegexOutput { /// Parse and compile `pattern`, resulting in an existentially-typed capture list. public init(compiling pattern: String) throws { @@ -18,6 +19,7 @@ extension Regex where Output == AnyRegexOutput { } } +@available(SwiftStdlib 5.7, *) extension Regex { /// Parse and compile `pattern`, resulting in a strongly-typed capture list. public init( @@ -28,6 +30,7 @@ extension Regex { } } +@available(SwiftStdlib 5.7, *) extension Regex.Match where Output == AnyRegexOutput { // Ensures `.0` always refers to the whole match. public subscript( @@ -54,6 +57,7 @@ public struct AnyRegexOutput { } } +@available(SwiftStdlib 5.7, *) extension AnyRegexOutput { /// Creates a type-erased regex output from an existing output. /// @@ -87,6 +91,7 @@ extension AnyRegexOutput { } } +@available(SwiftStdlib 5.7, *) extension AnyRegexOutput { internal init( input: String, elements: C @@ -95,6 +100,7 @@ extension AnyRegexOutput { } } +@available(SwiftStdlib 5.7, *) extension AnyRegexOutput.ElementRepresentation { init(_ element: StructuredCapture) { self.init( @@ -117,6 +123,7 @@ extension AnyRegexOutput.ElementRepresentation { } } +@available(SwiftStdlib 5.7, *) extension AnyRegexOutput: RandomAccessCollection { public struct Element { fileprivate let representation: ElementRepresentation @@ -163,6 +170,7 @@ extension AnyRegexOutput: RandomAccessCollection { } } +@available(SwiftStdlib 5.7, *) extension Regex.Match where Output == AnyRegexOutput { /// Creates a type-erased regex match from an existing match. /// diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index e2d222eba..a2cf76cd2 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -61,6 +61,7 @@ public struct Regex: RegexComponent { } } +@available(SwiftStdlib 5.7, *) extension Regex { /// A program representation that caches any lowered representation for /// execution. @@ -85,6 +86,7 @@ extension Regex { } } +@available(SwiftStdlib 5.7, *) extension Regex { @_spi(RegexBuilder) public var root: DSLTree.Node { @@ -95,5 +97,4 @@ extension Regex { public init(node: DSLTree.Node) { self.program = Program(tree: .init(node, options: nil)) } - } diff --git a/Sources/_StringProcessing/Regex/DSLConsumers.swift b/Sources/_StringProcessing/Regex/DSLConsumers.swift index c3dc6d88c..e1a69d74b 100644 --- a/Sources/_StringProcessing/Regex/DSLConsumers.swift +++ b/Sources/_StringProcessing/Regex/DSLConsumers.swift @@ -18,6 +18,7 @@ public protocol CustomRegexComponent: RegexComponent { ) -> (upperBound: String.Index, output: RegexOutput)? } +@available(SwiftStdlib 5.7, *) extension CustomRegexComponent { public var regex: Regex { Regex(node: .matcher(.init(RegexOutput.self), { input, index, bounds in diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index e43b3c1ee..189b3a22d 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -12,7 +12,6 @@ import _RegexParser @_spi(RegexBuilder) -@available(SwiftStdlib 5.7, *) public struct DSLTree { var root: Node var options: Options? @@ -165,7 +164,6 @@ extension DSLTree { // CollectionConsumer @_spi(RegexBuilder) -@available(SwiftStdlib 5.7, *) public typealias _ConsumerInterface = ( String, Range ) throws -> String.Index? @@ -173,14 +171,12 @@ public typealias _ConsumerInterface = ( // Type producing consume // TODO: better name @_spi(RegexBuilder) -@available(SwiftStdlib 5.7, *) public typealias _MatcherInterface = ( String, String.Index, Range ) throws -> (String.Index, Any)? // Character-set (post grapheme segmentation) @_spi(RegexBuilder) -@available(SwiftStdlib 5.7, *) public typealias _CharacterPredicateInterface = ( (Character) -> Bool ) @@ -381,7 +377,6 @@ extension DSLTree.Node { } @_spi(RegexBuilder) -@available(SwiftStdlib 5.7, *) public struct ReferenceID: Hashable, Equatable { private static var counter: Int = 0 var base: Int @@ -393,7 +388,6 @@ public struct ReferenceID: Hashable, Equatable { } @_spi(RegexBuilder) -@available(SwiftStdlib 5.7, *) public struct CaptureTransform: Hashable, CustomStringConvertible { public enum Closure { case failable((Substring) throws -> Any?) diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 73ae62b7e..251febc87 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -9,6 +9,7 @@ // //===----------------------------------------------------------------------===// +@available(SwiftStdlib 5.7, *) extension Regex { /// The result of matching a regex against a string. /// @@ -29,6 +30,7 @@ extension Regex { } } +@available(SwiftStdlib 5.7, *) extension Regex.Match { /// The produced output from the match operation public var output: Output { @@ -81,6 +83,7 @@ extension Regex.Match { } } +@available(SwiftStdlib 5.7, *) extension Regex { /// Match a string in its entirety. /// @@ -152,24 +155,29 @@ extension Regex { } } +@available(SwiftStdlib 5.7, *) extension String { public func wholeMatch( of r: R ) -> Regex.Match? { try? r.regex.wholeMatch(in: self) } + public func prefixMatch( of r: R ) -> Regex.Match? { try? r.regex.prefixMatch(in: self) } } + +@available(SwiftStdlib 5.7, *) extension Substring { public func wholeMatch( of r: R ) -> Regex.Match? { try? r.regex.wholeMatch(in: self) } + public func prefixMatch( of r: R ) -> Regex.Match? { diff --git a/Sources/_StringProcessing/Regex/Options.swift b/Sources/_StringProcessing/Regex/Options.swift index 8f48ba097..0e30140c8 100644 --- a/Sources/_StringProcessing/Regex/Options.swift +++ b/Sources/_StringProcessing/Regex/Options.swift @@ -11,6 +11,7 @@ import _RegexParser +@available(SwiftStdlib 5.7, *) extension RegexComponent { /// Returns a regular expression that ignores casing when matching. public func ignoringCase(_ ignoreCase: Bool = true) -> Regex { @@ -105,6 +106,7 @@ extension RegexComponent { } } +@available(SwiftStdlib 5.7, *) public struct RegexSemanticLevel: Hashable { internal enum Representation { case graphemeCluster @@ -127,6 +129,7 @@ public struct RegexSemanticLevel: Hashable { } // Options that only affect literals +@available(SwiftStdlib 5.7, *) extension RegexComponent { /// Returns a regular expression where the start and end of input /// anchors (`^` and `$`) also match against the start and end of a line. @@ -159,6 +162,8 @@ extension RegexComponent { } // MARK: - Helper method + +@available(SwiftStdlib 5.7, *) extension RegexComponent { fileprivate func wrapInOption( _ option: AST.MatchingOption.Kind, diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index e63423f8f..d160abc81 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -16,7 +16,6 @@ import _RegexParser // of parsing or to store in an AST @_spi(RegexBuilder) -@available(SwiftStdlib 5.7, *) public struct _CharacterClassModel: Hashable { /// The actual character class to match. var cc: Representation @@ -29,7 +28,7 @@ public struct _CharacterClassModel: Hashable { var isInverted: Bool = false // TODO: Split out builtin character classes into their own type? - public enum Representation: Hashable { + public enum Representation: Hashable { /// Any character case any /// Any grapheme cluster @@ -56,8 +55,7 @@ public struct _CharacterClassModel: Hashable { public typealias SetOperator = AST.CustomCharacterClass.SetOp /// A binary set operation that forms a character class component. - @_spi(RegexBuilder) - public struct SetOperation: Hashable { + public struct SetOperation: Hashable { var lhs: CharacterSetComponent var op: SetOperator var rhs: CharacterSetComponent @@ -74,8 +72,7 @@ public struct _CharacterClassModel: Hashable { } } - @_spi(RegexBuilder) - public enum CharacterSetComponent: Hashable { + public enum CharacterSetComponent: Hashable { case character(Character) case range(ClosedRange) @@ -205,6 +202,7 @@ public struct _CharacterClassModel: Hashable { } } +@available(SwiftStdlib 5.7, *) extension _CharacterClassModel: RegexComponent { public typealias RegexOutput = Substring @@ -374,7 +372,7 @@ extension _CharacterClassModel { } extension DSLTree.Atom { - var characterClass: _CharacterClassModel? { + var characterClass: _CharacterClassModel? { switch self { case let .unconverted(a): return a.characterClass @@ -385,7 +383,7 @@ extension DSLTree.Atom { } extension AST.Atom { - var characterClass: _CharacterClassModel? { + var characterClass: _CharacterClassModel? { switch kind { case let .escaped(b): return b.characterClass @@ -411,7 +409,7 @@ extension AST.Atom { } extension AST.Atom.EscapedBuiltin { - var characterClass: _CharacterClassModel? { + var characterClass: _CharacterClassModel? { switch self { case .decimalDigit: return .digit case .notDecimalDigit: return .digit.inverted From dfec8fbcfd836f21598b7b08a3c6c5f8f750a169 Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Fri, 15 Apr 2022 13:20:57 -0700 Subject: [PATCH 071/133] Import _RegexParser as implementation only --- Sources/_StringProcessing/ByteCodeGen.swift | 2 +- Sources/_StringProcessing/Capture.swift | 2 +- Sources/_StringProcessing/Compiler.swift | 2 +- Sources/_StringProcessing/ConsumerInterface.swift | 2 +- Sources/_StringProcessing/Engine/MEBuilder.swift | 2 +- Sources/_StringProcessing/Engine/MECapture.swift | 2 +- Sources/_StringProcessing/Engine/MEProgram.swift | 2 +- Sources/_StringProcessing/Engine/Registers.swift | 2 +- Sources/_StringProcessing/Engine/Structuralize.swift | 2 +- Sources/_StringProcessing/Executor.swift | 2 +- Sources/_StringProcessing/MatchingOptions.swift | 2 +- Sources/_StringProcessing/PrintAsPattern.swift | 3 ++- Sources/_StringProcessing/Regex/ASTConversion.swift | 2 +- Sources/_StringProcessing/Regex/AnyRegexOutput.swift | 2 +- Sources/_StringProcessing/Regex/Core.swift | 2 +- Sources/_StringProcessing/Regex/DSLTree.swift | 2 +- Sources/_StringProcessing/Regex/Options.swift | 2 +- Sources/_StringProcessing/Utility/ASTBuilder.swift | 2 +- Sources/_StringProcessing/_CharacterClassModel.swift | 2 +- 19 files changed, 20 insertions(+), 19 deletions(-) diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index c44b5af94..c8cf0805c 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -1,4 +1,4 @@ -import _RegexParser +@_implementationOnly import _RegexParser extension Compiler { struct ByteCodeGen { diff --git a/Sources/_StringProcessing/Capture.swift b/Sources/_StringProcessing/Capture.swift index f7dff424e..51428acee 100644 --- a/Sources/_StringProcessing/Capture.swift +++ b/Sources/_StringProcessing/Capture.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser /// A structured capture struct StructuredCapture { diff --git a/Sources/_StringProcessing/Compiler.swift b/Sources/_StringProcessing/Compiler.swift index 90192bdaf..96476f42b 100644 --- a/Sources/_StringProcessing/Compiler.swift +++ b/Sources/_StringProcessing/Compiler.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser class Compiler { let tree: DSLTree diff --git a/Sources/_StringProcessing/ConsumerInterface.swift b/Sources/_StringProcessing/ConsumerInterface.swift index b49804ca1..ecb7d1356 100644 --- a/Sources/_StringProcessing/ConsumerInterface.swift +++ b/Sources/_StringProcessing/ConsumerInterface.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser extension DSLTree.Node { /// Attempt to generate a consumer from this AST node diff --git a/Sources/_StringProcessing/Engine/MEBuilder.swift b/Sources/_StringProcessing/Engine/MEBuilder.swift index 2b849874b..7cf94f6ef 100644 --- a/Sources/_StringProcessing/Engine/MEBuilder.swift +++ b/Sources/_StringProcessing/Engine/MEBuilder.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser // For errors +@_implementationOnly import _RegexParser // For errors extension MEProgram where Input.Element: Hashable { struct Builder { diff --git a/Sources/_StringProcessing/Engine/MECapture.swift b/Sources/_StringProcessing/Engine/MECapture.swift index 301212736..390af7d66 100644 --- a/Sources/_StringProcessing/Engine/MECapture.swift +++ b/Sources/_StringProcessing/Engine/MECapture.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser /* diff --git a/Sources/_StringProcessing/Engine/MEProgram.swift b/Sources/_StringProcessing/Engine/MEProgram.swift index ecd67d4ba..b0f2e6a79 100644 --- a/Sources/_StringProcessing/Engine/MEProgram.swift +++ b/Sources/_StringProcessing/Engine/MEProgram.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser struct MEProgram where Input.Element: Equatable { typealias ConsumeFunction = (Input, Range) -> Input.Index? diff --git a/Sources/_StringProcessing/Engine/Registers.swift b/Sources/_StringProcessing/Engine/Registers.swift index a2a5be104..bc17f1215 100644 --- a/Sources/_StringProcessing/Engine/Registers.swift +++ b/Sources/_StringProcessing/Engine/Registers.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser struct SentinelValue: Hashable, CustomStringConvertible { var description: String { "" } diff --git a/Sources/_StringProcessing/Engine/Structuralize.swift b/Sources/_StringProcessing/Engine/Structuralize.swift index 02a03c09c..12d2e1242 100644 --- a/Sources/_StringProcessing/Engine/Structuralize.swift +++ b/Sources/_StringProcessing/Engine/Structuralize.swift @@ -1,4 +1,4 @@ -import _RegexParser +@_implementationOnly import _RegexParser extension CaptureStructure { var optionalCount: Int { diff --git a/Sources/_StringProcessing/Executor.swift b/Sources/_StringProcessing/Executor.swift index d911c3512..c7d4527a5 100644 --- a/Sources/_StringProcessing/Executor.swift +++ b/Sources/_StringProcessing/Executor.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser struct Executor { // TODO: consider let, for now lets us toggle tracing diff --git a/Sources/_StringProcessing/MatchingOptions.swift b/Sources/_StringProcessing/MatchingOptions.swift index 0f244f1b8..8213185c1 100644 --- a/Sources/_StringProcessing/MatchingOptions.swift +++ b/Sources/_StringProcessing/MatchingOptions.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser /// A type that represents the current state of regex matching options, with /// stack-based scoping. diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index 8e1dd8322..edf4fad40 100644 --- a/Sources/_StringProcessing/PrintAsPattern.swift +++ b/Sources/_StringProcessing/PrintAsPattern.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser // TODO: Add an expansion level, both from top to bottom. // After `printAsCanonical` is fleshed out, these two @@ -17,6 +17,7 @@ import _RegexParser // incremental conversion, such that leaves remain // as canonical regex literals. +@_spi(PatternConverter) extension AST { /// Render as a Pattern DSL @_spi(PatternConverter) diff --git a/Sources/_StringProcessing/Regex/ASTConversion.swift b/Sources/_StringProcessing/Regex/ASTConversion.swift index ac88dcd73..d32770eae 100644 --- a/Sources/_StringProcessing/Regex/ASTConversion.swift +++ b/Sources/_StringProcessing/Regex/ASTConversion.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser extension AST { var dslTree: DSLTree { diff --git a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift index 16829ff78..06241c7ea 100644 --- a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift +++ b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser @available(SwiftStdlib 5.7, *) extension Regex where Output == AnyRegexOutput { diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index a2cf76cd2..56a14da51 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser /// A type that represents a regular expression. diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index 189b3a22d..6bf4ec47c 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser @_spi(RegexBuilder) public struct DSLTree { diff --git a/Sources/_StringProcessing/Regex/Options.swift b/Sources/_StringProcessing/Regex/Options.swift index 0e30140c8..d474caae3 100644 --- a/Sources/_StringProcessing/Regex/Options.swift +++ b/Sources/_StringProcessing/Regex/Options.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser @available(SwiftStdlib 5.7, *) extension RegexComponent { diff --git a/Sources/_StringProcessing/Utility/ASTBuilder.swift b/Sources/_StringProcessing/Utility/ASTBuilder.swift index c14454a5c..51d4f8bfc 100644 --- a/Sources/_StringProcessing/Utility/ASTBuilder.swift +++ b/Sources/_StringProcessing/Utility/ASTBuilder.swift @@ -25,7 +25,7 @@ AST. */ -import _RegexParser +@_implementationOnly import _RegexParser func alt(_ asts: [AST.Node]) -> AST.Node { return .alternation( diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index d160abc81..c9762f00e 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser // NOTE: This is a model type. We want to be able to get one from // an AST, but this isn't a natural thing to produce in the context From 3293905ad0922b13bbc071650c99a2eb50786244 Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Fri, 15 Apr 2022 22:03:03 -0700 Subject: [PATCH 072/133] Fix release build. Move Prototypes to a test target so that it's not built under the release configuration. Disable the PEG prototype in Exercises since it depends on Prototypes. Resolves #288. --- Package.swift | 4 ++-- Sources/Exercises/Exercises.swift | 1 - Sources/Exercises/Participants/PEGParticipant.swift | 4 ++++ {Sources => Tests}/Prototypes/CMakeLists.txt | 0 {Sources => Tests}/Prototypes/Combinators/Combinators.swift | 0 {Sources => Tests}/Prototypes/PEG/PEG.swift | 0 {Sources => Tests}/Prototypes/PEG/PEGCode.swift | 0 {Sources => Tests}/Prototypes/PEG/PEGCompile.swift | 0 {Sources => Tests}/Prototypes/PEG/PEGCore.swift | 0 {Sources => Tests}/Prototypes/PEG/PEGInterpreter.swift | 0 {Sources => Tests}/Prototypes/PEG/PEGTranspile.swift | 0 {Sources => Tests}/Prototypes/PEG/PEGVM.swift | 0 {Sources => Tests}/Prototypes/PEG/PEGVMExecute.swift | 0 {Sources => Tests}/Prototypes/PEG/Printing.swift | 0 {Sources => Tests}/Prototypes/PTCaRet/Interpreter.swift | 0 {Sources => Tests}/Prototypes/PTCaRet/PTCaRet.swift | 0 .../Prototypes/TourOfTypes/CharacterClass.swift | 0 {Sources => Tests}/Prototypes/TourOfTypes/Literal.swift | 0 18 files changed, 6 insertions(+), 3 deletions(-) rename {Sources => Tests}/Prototypes/CMakeLists.txt (100%) rename {Sources => Tests}/Prototypes/Combinators/Combinators.swift (100%) rename {Sources => Tests}/Prototypes/PEG/PEG.swift (100%) rename {Sources => Tests}/Prototypes/PEG/PEGCode.swift (100%) rename {Sources => Tests}/Prototypes/PEG/PEGCompile.swift (100%) rename {Sources => Tests}/Prototypes/PEG/PEGCore.swift (100%) rename {Sources => Tests}/Prototypes/PEG/PEGInterpreter.swift (100%) rename {Sources => Tests}/Prototypes/PEG/PEGTranspile.swift (100%) rename {Sources => Tests}/Prototypes/PEG/PEGVM.swift (100%) rename {Sources => Tests}/Prototypes/PEG/PEGVMExecute.swift (100%) rename {Sources => Tests}/Prototypes/PEG/Printing.swift (100%) rename {Sources => Tests}/Prototypes/PTCaRet/Interpreter.swift (100%) rename {Sources => Tests}/Prototypes/PTCaRet/PTCaRet.swift (100%) rename {Sources => Tests}/Prototypes/TourOfTypes/CharacterClass.swift (100%) rename {Sources => Tests}/Prototypes/TourOfTypes/Literal.swift (100%) diff --git a/Package.swift b/Package.swift index 26b7f90af..f8162e762 100644 --- a/Package.swift +++ b/Package.swift @@ -76,7 +76,7 @@ let package = Package( .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) ]), - .target( + .testTarget( name: "Prototypes", dependencies: ["_RegexParser", "_StringProcessing"], swiftSettings: [ @@ -100,7 +100,7 @@ let package = Package( // MARK: Exercises .target( name: "Exercises", - dependencies: ["_RegexParser", "Prototypes", "_StringProcessing", "RegexBuilder"], + dependencies: ["_RegexParser", "_StringProcessing", "RegexBuilder"], swiftSettings: [ .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) diff --git a/Sources/Exercises/Exercises.swift b/Sources/Exercises/Exercises.swift index f9801ca90..17c1eeb56 100644 --- a/Sources/Exercises/Exercises.swift +++ b/Sources/Exercises/Exercises.swift @@ -16,7 +16,6 @@ public enum Exercises { HandWrittenParticipant.self, RegexDSLParticipant.self, RegexLiteralParticipant.self, - PEGParticipant.self, NSREParticipant.self, ] } diff --git a/Sources/Exercises/Participants/PEGParticipant.swift b/Sources/Exercises/Participants/PEGParticipant.swift index 21bec6a7c..8987b6b0c 100644 --- a/Sources/Exercises/Participants/PEGParticipant.swift +++ b/Sources/Exercises/Participants/PEGParticipant.swift @@ -9,6 +9,9 @@ // //===----------------------------------------------------------------------===// +// Disabled because Prototypes is a test target. +#if false + struct PEGParticipant: Participant { static var name: String { "PEG" } } @@ -51,3 +54,4 @@ private func graphemeBreakPropertyData(forLine line: String) -> GraphemeBreakEnt } +#endif diff --git a/Sources/Prototypes/CMakeLists.txt b/Tests/Prototypes/CMakeLists.txt similarity index 100% rename from Sources/Prototypes/CMakeLists.txt rename to Tests/Prototypes/CMakeLists.txt diff --git a/Sources/Prototypes/Combinators/Combinators.swift b/Tests/Prototypes/Combinators/Combinators.swift similarity index 100% rename from Sources/Prototypes/Combinators/Combinators.swift rename to Tests/Prototypes/Combinators/Combinators.swift diff --git a/Sources/Prototypes/PEG/PEG.swift b/Tests/Prototypes/PEG/PEG.swift similarity index 100% rename from Sources/Prototypes/PEG/PEG.swift rename to Tests/Prototypes/PEG/PEG.swift diff --git a/Sources/Prototypes/PEG/PEGCode.swift b/Tests/Prototypes/PEG/PEGCode.swift similarity index 100% rename from Sources/Prototypes/PEG/PEGCode.swift rename to Tests/Prototypes/PEG/PEGCode.swift diff --git a/Sources/Prototypes/PEG/PEGCompile.swift b/Tests/Prototypes/PEG/PEGCompile.swift similarity index 100% rename from Sources/Prototypes/PEG/PEGCompile.swift rename to Tests/Prototypes/PEG/PEGCompile.swift diff --git a/Sources/Prototypes/PEG/PEGCore.swift b/Tests/Prototypes/PEG/PEGCore.swift similarity index 100% rename from Sources/Prototypes/PEG/PEGCore.swift rename to Tests/Prototypes/PEG/PEGCore.swift diff --git a/Sources/Prototypes/PEG/PEGInterpreter.swift b/Tests/Prototypes/PEG/PEGInterpreter.swift similarity index 100% rename from Sources/Prototypes/PEG/PEGInterpreter.swift rename to Tests/Prototypes/PEG/PEGInterpreter.swift diff --git a/Sources/Prototypes/PEG/PEGTranspile.swift b/Tests/Prototypes/PEG/PEGTranspile.swift similarity index 100% rename from Sources/Prototypes/PEG/PEGTranspile.swift rename to Tests/Prototypes/PEG/PEGTranspile.swift diff --git a/Sources/Prototypes/PEG/PEGVM.swift b/Tests/Prototypes/PEG/PEGVM.swift similarity index 100% rename from Sources/Prototypes/PEG/PEGVM.swift rename to Tests/Prototypes/PEG/PEGVM.swift diff --git a/Sources/Prototypes/PEG/PEGVMExecute.swift b/Tests/Prototypes/PEG/PEGVMExecute.swift similarity index 100% rename from Sources/Prototypes/PEG/PEGVMExecute.swift rename to Tests/Prototypes/PEG/PEGVMExecute.swift diff --git a/Sources/Prototypes/PEG/Printing.swift b/Tests/Prototypes/PEG/Printing.swift similarity index 100% rename from Sources/Prototypes/PEG/Printing.swift rename to Tests/Prototypes/PEG/Printing.swift diff --git a/Sources/Prototypes/PTCaRet/Interpreter.swift b/Tests/Prototypes/PTCaRet/Interpreter.swift similarity index 100% rename from Sources/Prototypes/PTCaRet/Interpreter.swift rename to Tests/Prototypes/PTCaRet/Interpreter.swift diff --git a/Sources/Prototypes/PTCaRet/PTCaRet.swift b/Tests/Prototypes/PTCaRet/PTCaRet.swift similarity index 100% rename from Sources/Prototypes/PTCaRet/PTCaRet.swift rename to Tests/Prototypes/PTCaRet/PTCaRet.swift diff --git a/Sources/Prototypes/TourOfTypes/CharacterClass.swift b/Tests/Prototypes/TourOfTypes/CharacterClass.swift similarity index 100% rename from Sources/Prototypes/TourOfTypes/CharacterClass.swift rename to Tests/Prototypes/TourOfTypes/CharacterClass.swift diff --git a/Sources/Prototypes/TourOfTypes/Literal.swift b/Tests/Prototypes/TourOfTypes/Literal.swift similarity index 100% rename from Sources/Prototypes/TourOfTypes/Literal.swift rename to Tests/Prototypes/TourOfTypes/Literal.swift From c6cdf6cd062cf8b3ca65f101e3cb5912edbf29d0 Mon Sep 17 00:00:00 2001 From: I-Ting Tina Liu Date: Wed, 13 Apr 2022 08:13:41 -0700 Subject: [PATCH 073/133] Throwing matches and update to CustomMatchingRegexComponent - Update the name `CustomRegexComponent` to `CustomMatchingRegexComponent` per pitch - Adopt `throws` for `CustomMatchingRegexComponent` as added in #261. Errors thrown by `CustomMatchingRegexComponent`'s conformers will be bubbled up to the engine and surfaced at client-side. --- .../Evolution/StringProcessingAlgorithms.md | 2 +- Sources/_StringProcessing/ByteCodeGen.swift | 4 +- .../Regex/DSLConsumers.swift | 14 +- Tests/RegexBuilderTests/CustomTests.swift | 249 +++++++++++++++++- Tests/RegexBuilderTests/RegexDSLTests.swift | 8 +- 5 files changed, 263 insertions(+), 14 deletions(-) diff --git a/Documentation/Evolution/StringProcessingAlgorithms.md b/Documentation/Evolution/StringProcessingAlgorithms.md index 9454396ce..b976c562e 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -187,7 +187,7 @@ public protocol CustomMatchingRegexComponent : RegexComponent { _ input: String, startingAt index: String.Index, in bounds: Range - ) -> (upperBound: String.Index, match: Match)? + ) throws -> (upperBound: String.Index, match: Match)? } ``` diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index c44b5af94..8f111e627 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -302,7 +302,9 @@ extension Compiler.ByteCodeGen { // not captured. This may mean we should store // an existential instead of a closure... - let matcher = builder.makeMatcherFunction(matcher) + let matcher = builder.makeMatcherFunction { input, start, range in + try matcher(input, start, range) + } let valReg = builder.makeValueRegister() builder.buildMatcher(matcher, into: valReg) diff --git a/Sources/_StringProcessing/Regex/DSLConsumers.swift b/Sources/_StringProcessing/Regex/DSLConsumers.swift index e1a69d74b..ea46c789b 100644 --- a/Sources/_StringProcessing/Regex/DSLConsumers.swift +++ b/Sources/_StringProcessing/Regex/DSLConsumers.swift @@ -10,19 +10,21 @@ //===----------------------------------------------------------------------===// @available(SwiftStdlib 5.7, *) -public protocol CustomRegexComponent: RegexComponent { +public protocol CustomMatchingRegexComponent: RegexComponent { func match( _ input: String, startingAt index: String.Index, in bounds: Range - ) -> (upperBound: String.Index, output: RegexOutput)? + ) throws -> (upperBound: String.Index, output: RegexOutput)? } @available(SwiftStdlib 5.7, *) -extension CustomRegexComponent { +extension CustomMatchingRegexComponent { public var regex: Regex { - Regex(node: .matcher(.init(RegexOutput.self), { input, index, bounds in - match(input, startingAt: index, in: bounds) - })) + + let node: DSLTree.Node = .matcher(.init(RegexOutput.self), { input, index, bounds in + try match(input, startingAt: index, in: bounds) + }) + return Regex(node: node) } } diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index 0ac6b46c5..0a7d6fc59 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -14,7 +14,7 @@ import _StringProcessing @testable import RegexBuilder // A nibbler processes a single character from a string -private protocol Nibbler: CustomRegexComponent { +private protocol Nibbler: CustomMatchingRegexComponent { func nibble(_: Character) -> RegexOutput? } @@ -24,7 +24,7 @@ extension Nibbler { _ input: String, startingAt index: String.Index, in bounds: Range - ) -> (upperBound: String.Index, output: RegexOutput)? { + ) throws -> (upperBound: String.Index, output: RegexOutput)? { guard index != bounds.upperBound, let res = nibble(input[index]) else { return nil } @@ -49,6 +49,69 @@ private struct Asciibbler: Nibbler { } } +private struct IntParser: CustomMatchingRegexComponent { + struct ParseError: Error, Hashable {} + typealias RegexOutput = Int + func match(_ input: String, + startingAt index: String.Index, + in bounds: Range + ) throws -> (upperBound: String.Index, output: Int)? { + guard index != bounds.upperBound else { return nil } + + let r = Regex { + Capture(OneOrMore(.digit)) { Int($0) } + } + + guard let match = input[index.. + ) throws -> (upperBound: String.Index, output: Currency)? { + + guard index != bounds.upperBound else { return nil } + + let substr = input[index..( + _ regex: Regex, + _ tests: (input: String, match: Match?, expectError: E?)..., + file: StaticString = #file, + line: UInt = #line + ) { + for (input, match, expectError) in tests { + do { + let result = try regex.wholeMatch(in: input)?.output + XCTAssertEqual(result, match) + } catch let e as E { + XCTAssertEqual(e, expectError) + } catch { + XCTFail() + } + } + } + + func customTest( + _ regex: Regex, + _ tests: (input: String, match: Match?, expectError1: Error1?, expectError2: Error2?)..., + file: StaticString = #file, + line: UInt = #line + ) { + for (input, match, expectError1, expectError2) in tests { + do { + let result = try regex.wholeMatch(in: input)?.output + XCTAssertEqual(result, match) + } catch let e as Error1 { + XCTAssertEqual(e, expectError1, input, file: file, line: line) + } catch let e as Error2 { + XCTAssertEqual(e, expectError2, input, file: file, line: line) + } catch { + XCTFail("caught error: \(error.localizedDescription)") + } + } + } + + func customTest( + _ regex: Regex<(Substring, Capture)>, + _ tests: (input: String, match: (Substring, Capture)?, expectError1: Error1?, expectError2: Error2?)..., + file: StaticString = #file, + line: UInt = #line + ) { + for (input, match, expectError1, expectError2) in tests { + do { + let result = try regex.wholeMatch(in: input)?.output + XCTAssertEqual(result?.0, match?.0, file: file, line: line) + XCTAssertEqual(result?.1, match?.1, file: file, line: line) + } catch let e as Error1 { + XCTAssertEqual(e, expectError1, input, file: file, line: line) + } catch let e as Error2 { + XCTAssertEqual(e, expectError2, input, file: file, line: line) + } catch { + XCTFail("caught error: \(error.localizedDescription)") + } + } + } + + func customTest( + _ regex: Regex<(Substring, Capture1, Capture2)>, + _ tests: (input: String, match: (Substring, Capture1, Capture2)?, expectError1: Error1?, expectError2: Error2?)..., + file: StaticString = #file, + line: UInt = #line + ) { + for (input, match, expectError1, expectError2) in tests { + do { + let result = try regex.wholeMatch(in: input)?.output + XCTAssertEqual(result?.0, match?.0, file: file, line: line) + XCTAssertEqual(result?.1, match?.1, file: file, line: line) + XCTAssertEqual(result?.2, match?.2, file: file, line: line) + } catch let e as Error1 { + XCTAssertEqual(e, expectError1, input, file: file, line: line) + } catch let e as Error2 { + XCTAssertEqual(e, expectError2, input, file: file, line: line) + } catch { + XCTFail("caught error: \(error.localizedDescription)") + } + } + } + + // No capture, one error + customTest( + Regex { + IntParser() + }, + ("zzz", nil, IntParser.ParseError()), + ("x10x", nil, IntParser.ParseError()), + ("30", 30, nil) + ) + + customTest( + Regex { + CurrencyParser() + }, + ("USD", .usd, nil), + ("NTD", .ntd, nil), + ("NTD USD", nil, nil), + ("DEM", nil, CurrencyParser.ParseError.deprecated), + ("XXX", nil, CurrencyParser.ParseError.unrecognized) + ) + + // No capture, two errors + customTest( + Regex { + IntParser() + " " + IntParser() + }, + ("20304 100", "20304 100", nil, nil), + ("20304.445 200", nil, IntParser.ParseError(), nil), + ("20304 200.123", nil, nil, IntParser.ParseError()), + ("20304.445 200.123", nil, IntParser.ParseError(), IntParser.ParseError()) + ) + + customTest( + Regex { + CurrencyParser() + IntParser() + }, + ("USD100", "USD100", nil, nil), + ("XXX100", nil, CurrencyParser.ParseError.unrecognized, nil), + ("USD100.000", nil, nil, IntParser.ParseError()), + ("XXX100.0000", nil, CurrencyParser.ParseError.unrecognized, IntParser.ParseError()) + ) + + // One capture, two errors: One error is thrown from inside a capture, + // while the other one is thrown from outside + customTest( + Regex { + Capture { CurrencyParser() } + IntParser() + }, + ("USD100", ("USD100", .usd), nil, nil), + ("NTD305.5", nil, nil, IntParser.ParseError()), + ("DEM200", ("DEM200", .dem), CurrencyParser.ParseError.deprecated, nil), + ("XXX", nil, CurrencyParser.ParseError.unrecognized, IntParser.ParseError()) + ) + + customTest( + Regex { + CurrencyParser() + Capture { IntParser() } + }, + ("USD100", ("USD100", 100), nil, nil), + ("NTD305.5", nil, nil, IntParser.ParseError()), + ("DEM200", ("DEM200", 200), CurrencyParser.ParseError.deprecated, nil), + ("XXX", nil, CurrencyParser.ParseError.unrecognized, IntParser.ParseError()) + ) + + // One capture, two errors: Both errors are thrown from inside the capture + customTest( + Regex { + Capture { + CurrencyParser() + IntParser() + } + }, + ("USD100", ("USD100", "USD100"), nil, nil), + ("NTD305.5", nil, nil, IntParser.ParseError()), + ("DEM200", ("DEM200", "DEM200"), CurrencyParser.ParseError.deprecated, nil), + ("XXX", nil, CurrencyParser.ParseError.unrecognized, IntParser.ParseError()) + ) + + // Two captures, two errors: Different erros are thrown from inside captures + customTest( + Regex { + Capture(CurrencyParser()) + Capture(IntParser()) + }, + ("USD100", ("USD100", .usd, 100), nil, nil), + ("NTD500", ("NTD500", .ntd, 500), nil, nil), + ("XXX20", nil, CurrencyParser.ParseError.unrecognized, IntParser.ParseError()), + ("DEM500", nil, CurrencyParser.ParseError.deprecated, nil), + ("DEM500.345", nil, CurrencyParser.ParseError.deprecated, IntParser.ParseError()), + ("NTD100.345", nil, nil, IntParser.ParseError()) + ) + + } } diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index b38b82a33..8159ba8ae 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -743,13 +743,13 @@ class RegexDSLTests: XCTestCase { var patch: Int var dev: String? } - struct SemanticVersionParser: CustomRegexComponent { + struct SemanticVersionParser: CustomMatchingRegexComponent { typealias RegexOutput = SemanticVersion func match( _ input: String, startingAt index: String.Index, in bounds: Range - ) -> (upperBound: String.Index, output: SemanticVersion)? { + ) throws -> (upperBound: String.Index, output: SemanticVersion)? { let regex = Regex { TryCapture(OneOrMore(.digit)) { Int($0) } "." @@ -776,13 +776,13 @@ class RegexDSLTests: XCTestCase { return (match.range.upperBound, result) } } - + let versions = [ ("1.0", SemanticVersion(major: 1, minor: 0, patch: 0)), ("1.0.1", SemanticVersion(major: 1, minor: 0, patch: 1)), ("12.100.5-dev", SemanticVersion(major: 12, minor: 100, patch: 5, dev: "dev")), ] - + let parser = SemanticVersionParser() for (str, version) in versions { XCTAssertEqual(str.wholeMatch(of: parser)?.output, version) From a342405b109e67bc271ace867edb5171bcfc1f52 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Mon, 18 Apr 2022 10:46:43 -0500 Subject: [PATCH 074/133] Add Substring algorithms tests (#289) `firstMatch(of:)` was ignoring the start/endIndex when searching in substrings; this change fixes that issue. Also adds the 'in' label to `Regex.firstMatch(in:Substring)` to match the rest of the related APIs. --- .../Algorithms/Matching/FirstMatch.swift | 2 +- Sources/_StringProcessing/Regex/Match.swift | 2 +- Tests/RegexTests/AlgorithmsTests.swift | 47 +++++++++++++++---- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift index a4dce19b7..cb527f948 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift @@ -61,6 +61,6 @@ extension BidirectionalCollection where SubSequence == Substring { of r: R ) -> Regex.Match? { let slice = self[...] - return try? r.regex.firstMatch(in: slice.base) + return try? r.regex.firstMatch(in: slice) } } diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 251febc87..a86899041 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -123,7 +123,7 @@ extension Regex { /// Find the first match in a substring /// /// Returns `nil` if no match is found and throws on abort - public func firstMatch(_ s: Substring) throws -> Regex.Match? { + public func firstMatch(in s: Substring) throws -> Regex.Match? { try _firstMatch(s.base, in: s.startIndex..] = string[...].ranges(of: regex).map { - let start = string.offset(ofIndex: $0.lowerBound) - let end = string.offset(ofIndex: $0.upperBound) - return start..] = string[...].ranges(of: regex).map(string.offsets(of:)) XCTAssertEqual(actualSeq, expected, file: file, line: line) // `IndexingIterator` tests the collection conformance - let actualCol: [Range] = string[...].ranges(of: regex)[...].map { - let start = string.offset(ofIndex: $0.lowerBound) - let end = string.offset(ofIndex: $0.upperBound) - return start..] = string[...].ranges(of: regex)[...].map(string.offsets(of:)) XCTAssertEqual(actualCol, expected, file: file, line: line) } @@ -145,4 +137,39 @@ class RegexConsumerTests: XCTestCase { XCTAssertEqual("x", "axb".trimming(r)) XCTAssertEqual("x", "axbb".trimming(r)) } + + func testSubstring() throws { + let s = "aaa | aaaaaa | aaaaaaaaaa" + let s1 = s.dropFirst(6) // "aaaaaa | aaaaaaaaaa" + let s2 = s1.dropLast(17) // "aa" + let regex = try! Regex(compiling: "a+") + + XCTAssertEqual(s.firstMatch(of: regex)?.0, "aaa") + XCTAssertEqual(s1.firstMatch(of: regex)?.0, "aaaaaa") + XCTAssertEqual(s2.firstMatch(of: regex)?.0, "aa") + + XCTAssertEqual( + s.ranges(of: regex).map(s.offsets(of:)), + [0..<3, 6..<12, 15..<25]) + XCTAssertEqual( + s1.ranges(of: regex).map(s.offsets(of:)), + [6..<12, 15..<25]) + XCTAssertEqual( + s2.ranges(of: regex).map(s.offsets(of:)), + [6..<8]) + + XCTAssertEqual(s.replacing(regex, with: ""), " | | ") + XCTAssertEqual(s1.replacing(regex, with: ""), " | ") + XCTAssertEqual(s2.replacing(regex, with: ""), "") + + XCTAssertEqual( + s._matches(of: regex).map(\.0), + ["aaa", "aaaaaa", "aaaaaaaaaa"]) + XCTAssertEqual( + s1._matches(of: regex).map(\.0), + ["aaaaaa", "aaaaaaaaaa"]) + XCTAssertEqual( + s2._matches(of: regex).map(\.0), + ["aa"]) + } } From fea6fe271c62ff1a3c42acf6e4ec7500941c26e7 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Mon, 18 Apr 2022 14:47:39 -0500 Subject: [PATCH 075/133] RegexBuilder quantifiers take an optional behavior (#293) --- Sources/RegexBuilder/DSL.swift | 16 +- Sources/RegexBuilder/Variadics.swift | 440 ++++++++++-------- .../VariadicsGenerator.swift | 20 +- Sources/_StringProcessing/ByteCodeGen.swift | 18 +- .../_StringProcessing/PrintAsPattern.swift | 11 + .../Regex/ASTConversion.swift | 2 +- Sources/_StringProcessing/Regex/DSLTree.swift | 12 +- Sources/_StringProcessing/Regex/Options.swift | 59 ++- Tests/RegexBuilderTests/RegexDSLTests.swift | 20 +- 9 files changed, 355 insertions(+), 243 deletions(-) diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 3c5f5ab5f..86ec0bee5 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -120,27 +120,29 @@ extension DSLTree.Node { @available(SwiftStdlib 5.7, *) static func repeating( _ range: Range, - _ behavior: QuantificationBehavior, + _ behavior: QuantificationBehavior?, _ node: DSLTree.Node ) -> DSLTree.Node { // TODO: Throw these as errors assert(range.lowerBound >= 0, "Cannot specify a negative lower bound") assert(!range.isEmpty, "Cannot specify an empty range") + + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default switch (range.lowerBound, range.upperBound) { case (0, Int.max): // 0... - return .quantification(.zeroOrMore, behavior.astKind, node) + return .quantification(.zeroOrMore, kind, node) case (1, Int.max): // 1... - return .quantification(.oneOrMore, behavior.astKind, node) + return .quantification(.oneOrMore, kind, node) case _ where range.count == 1: // ..<1 or ...0 or any range with count == 1 // Note: `behavior` is ignored in this case - return .quantification(.exactly(.init(faking: range.lowerBound)), .eager, node) + return .quantification(.exactly(.init(faking: range.lowerBound)), .default, node) case (0, _): // 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == Substring { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -627,10 +628,11 @@ extension Optionally { @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == Substring { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -640,7 +642,7 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) @@ -649,9 +651,10 @@ extension ZeroOrMore { @_disfavoredOverload public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == Substring { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -660,10 +663,11 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == Substring { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -674,9 +678,10 @@ extension OneOrMore { @_disfavoredOverload public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == Substring { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -685,10 +690,11 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == Substring { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -703,7 +709,7 @@ extension Repeat { ) where RegexOutput == Substring { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -714,7 +720,7 @@ extension Repeat { ) where RegexOutput == Substring { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) @@ -722,7 +728,7 @@ extension Repeat { public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == Substring, R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == Substring, R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -752,10 +759,11 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -765,7 +773,7 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?)> where Component.RegexOutput == (W, C0) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) @@ -773,9 +781,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -783,10 +792,11 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -796,9 +806,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -806,10 +817,11 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -823,7 +835,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -833,14 +845,14 @@ extension Repeat { ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -869,10 +882,11 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -882,7 +896,7 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?)> where Component.RegexOutput == (W, C0, C1) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) @@ -890,9 +904,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -900,10 +915,11 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -913,9 +929,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -923,10 +940,11 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -940,7 +958,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -950,14 +968,14 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -986,10 +1005,11 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -999,7 +1019,7 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?)> where Component.RegexOutput == (W, C0, C1, C2) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) @@ -1007,9 +1027,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1017,10 +1038,11 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1030,9 +1052,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1040,10 +1063,11 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1057,7 +1081,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1067,14 +1091,14 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1103,10 +1128,11 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1116,7 +1142,7 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.RegexOutput == (W, C0, C1, C2, C3) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) @@ -1124,9 +1150,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1134,10 +1161,11 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1147,9 +1175,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1157,10 +1186,11 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1174,7 +1204,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1184,14 +1214,14 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1220,10 +1251,11 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1233,7 +1265,7 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) @@ -1241,9 +1273,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1251,10 +1284,11 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1264,9 +1298,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1274,10 +1309,11 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1291,7 +1327,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1301,14 +1337,14 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1337,10 +1374,11 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1350,7 +1388,7 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) @@ -1358,9 +1396,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1368,10 +1407,11 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1381,9 +1421,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1391,10 +1432,11 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1408,7 +1450,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1418,14 +1460,14 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1454,10 +1497,11 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1467,7 +1511,7 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) @@ -1475,9 +1519,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1485,10 +1530,11 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1498,9 +1544,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1508,10 +1555,11 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1525,7 +1573,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1535,14 +1583,14 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1571,10 +1620,11 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1584,7 +1634,7 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) @@ -1592,9 +1642,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1602,10 +1653,11 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1615,9 +1667,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1625,10 +1678,11 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1642,7 +1696,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1652,14 +1706,14 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1688,10 +1743,11 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1701,7 +1757,7 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) @@ -1709,9 +1765,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1719,10 +1776,11 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1732,9 +1790,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1742,10 +1801,11 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1759,7 +1819,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1769,14 +1829,14 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1805,10 +1866,11 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1818,7 +1880,7 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) @@ -1826,9 +1888,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1836,10 +1899,11 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1849,9 +1913,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1859,10 +1924,11 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1876,7 +1942,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1886,14 +1952,14 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) \(params.whereClauseForInit) { - self.init(node: .quantification(.\(kind.astQuantifierAmount), behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.\(kind.astQuantifierAmount), kind, component.regex.root)) } } @@ -389,10 +390,11 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) \(params.disfavored)\ public init<\(params.genericParams)>( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @\(concatBuilderName) _ component: () -> Component ) \(params.whereClauseForInit) { - self.init(node: .quantification(.\(kind.astQuantifierAmount), behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.\(kind.astQuantifierAmount), kind, component().regex.root)) } } @@ -404,7 +406,7 @@ struct VariadicsGenerator: ParsableCommand { public static func buildLimitedAvailability<\(params.genericParams)>( _ component: Component ) -> \(regexTypeName)<\(params.matchType)> \(params.whereClause) { - .init(node: .quantification(.\(kind.astQuantifierAmount), .eager, component.regex.root)) + .init(node: .quantification(.\(kind.astQuantifierAmount), .default, component.regex.root)) } } """ : "") @@ -488,7 +490,7 @@ struct VariadicsGenerator: ParsableCommand { ) \(params.whereClauseForInit) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } \(defaultAvailableAttr) @@ -499,7 +501,7 @@ struct VariadicsGenerator: ParsableCommand { ) \(params.whereClauseForInit) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } \(defaultAvailableAttr) @@ -507,7 +509,7 @@ struct VariadicsGenerator: ParsableCommand { public init<\(params.genericParams), R: RangeExpression>( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) \(params.repeatingWhereClause) { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @\(concatBuilderName) _ component: () -> Component ) \(params.repeatingWhereClause) { self.init(node: .repeating(expression.relative(to: 0.. Regex { + wrapInOption(.multiline, addingIf: matchLineEndings) + } + + /// Returns a regular expression where quantifiers are reluctant by default + /// instead of eager. + /// + /// This method corresponds to applying the `U` option in a regular + /// expression literal. + /// + /// - Parameter useReluctantQuantifiers: A Boolean value indicating whether + /// quantifiers should be reluctant by default. + public func reluctantQuantifiers(_ useReluctantQuantifiers: Bool = true) -> Regex { + wrapInOption(.reluctantByDefault, addingIf: useReluctantQuantifiers) + } + /// Returns a regular expression that matches with the specified semantic /// level. /// @@ -128,39 +154,6 @@ public struct RegexSemanticLevel: Hashable { } } -// Options that only affect literals -@available(SwiftStdlib 5.7, *) -extension RegexComponent { - /// Returns a regular expression where the start and end of input - /// anchors (`^` and `$`) also match against the start and end of a line. - /// - /// This method corresponds to applying the `m` option in a regular - /// expression literal, and only applies to regular expressions specified as - /// literals. For this behavior in the `RegexBuilder` syntax, see - /// ``Anchor.startOfLine``, ``Anchor.endOfLine``, ``Anchor.startOfInput``, - /// and ``Anchor.endOfInput``. - /// - /// - Parameter matchLineEndings: A Boolean value indicating whether `^` and - /// `$` should match the start and end of lines, respectively. - public func anchorsMatchLineEndings(_ matchLineEndings: Bool = true) -> Regex { - wrapInOption(.multiline, addingIf: matchLineEndings) - } - - /// Returns a regular expression where quantifiers are reluctant by default - /// instead of eager. - /// - /// This method corresponds to applying the `U` option in a regular - /// expression literal, and only applies to regular expressions specified as - /// literals. In the `RegexBuilder` syntax, pass a ``QuantificationBehavior`` - /// value to any quantification method to change its behavior. - /// - /// - Parameter useReluctantCaptures: A Boolean value indicating whether - /// quantifiers should be reluctant by default. - public func reluctantCaptures(_ useReluctantCaptures: Bool = true) -> Regex { - wrapInOption(.reluctantByDefault, addingIf: useReluctantCaptures) - } -} - // MARK: - Helper method @available(SwiftStdlib 5.7, *) diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 8159ba8ae..3d8c4fc2c 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -262,6 +262,24 @@ class RegexDSLTests: XCTestCase { } .ignoringCase(false) } + + try _testDSLCaptures( + ("abcdef123", ("abcdef123", "a", "123")), + matchType: (Substring, Substring, Substring).self, ==) { + Capture { + // Reluctant behavior due to option + OneOrMore(.anyOf("abcd")) + .reluctantQuantifiers() + } + ZeroOrMore("a"..."z") + + Capture { + // Eager behavior due to explicit parameter, despite option + OneOrMore(.digit, .eagerly) + .reluctantQuantifiers() + } + ZeroOrMore(.digit) + } } func testQuantificationBehavior() throws { @@ -293,7 +311,7 @@ class RegexDSLTests: XCTestCase { OneOrMore(.word) Capture(.digit) ZeroOrMore(.any) - }.reluctantCaptures() + }.reluctantQuantifiers() } } #endif From 42641dab4694c60f9ad47ebc8236da3027523606 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Mon, 18 Apr 2022 15:46:21 -0500 Subject: [PATCH 076/133] Nominalize option methods (#295) --- Sources/_StringProcessing/Regex/Options.swift | 57 ++++++++++++++----- Tests/RegexBuilderTests/RegexDSLTests.swift | 46 +++++++++++++-- Tests/RegexTests/MatchTests.swift | 2 +- 3 files changed, 85 insertions(+), 20 deletions(-) diff --git a/Sources/_StringProcessing/Regex/Options.swift b/Sources/_StringProcessing/Regex/Options.swift index 2a612a1de..623589b54 100644 --- a/Sources/_StringProcessing/Regex/Options.swift +++ b/Sources/_StringProcessing/Regex/Options.swift @@ -14,40 +14,36 @@ @available(SwiftStdlib 5.7, *) extension RegexComponent { /// Returns a regular expression that ignores casing when matching. - public func ignoringCase(_ ignoreCase: Bool = true) -> Regex { - wrapInOption(.caseInsensitive, addingIf: ignoreCase) + public func ignoresCase(_ ignoresCase: Bool = true) -> Regex { + wrapInOption(.caseInsensitive, addingIf: ignoresCase) } /// Returns a regular expression that only matches ASCII characters as "word /// characters". - public func usingASCIIWordCharacters(_ useASCII: Bool = true) -> Regex { - wrapInOption(.asciiOnlyDigit, addingIf: useASCII) + public func asciiOnlyWordCharacters(_ useASCII: Bool = true) -> Regex { + wrapInOption(.asciiOnlyWord, addingIf: useASCII) } /// Returns a regular expression that only matches ASCII characters as digits. - public func usingASCIIDigits(_ useASCII: Bool = true) -> Regex { + public func asciiOnlyDigits(_ useASCII: Bool = true) -> Regex { wrapInOption(.asciiOnlyDigit, addingIf: useASCII) } /// Returns a regular expression that only matches ASCII characters as space /// characters. - public func usingASCIISpaces(_ useASCII: Bool = true) -> Regex { + public func asciiOnlyWhitespace(_ useASCII: Bool = true) -> Regex { wrapInOption(.asciiOnlySpace, addingIf: useASCII) } /// Returns a regular expression that only matches ASCII characters when /// matching character classes. - public func usingASCIICharacterClasses(_ useASCII: Bool = true) -> Regex { + public func asciiOnlyCharacterClasses(_ useASCII: Bool = true) -> Regex { wrapInOption(.asciiOnlyPOSIXProps, addingIf: useASCII) } - /// Returns a regular expression that uses the Unicode word boundary - /// algorithm. - /// - /// This option is enabled by default; pass `false` to disable use of - /// Unicode's word boundary algorithm. - public func usingUnicodeWordBoundaries(_ useUnicodeWordBoundaries: Bool = true) -> Regex { - wrapInOption(.unicodeWordBoundaries, addingIf: useUnicodeWordBoundaries) + /// Returns a regular expression that uses the specified word boundary algorithm. + public func wordBoundaryKind(_ wordBoundaryKind: RegexWordBoundaryKind) -> Regex { + wrapInOption(.unicodeWordBoundaries, addingIf: wordBoundaryKind == .unicodeLevel2) } /// Returns a regular expression where the start and end of input @@ -133,6 +129,7 @@ extension RegexComponent { } @available(SwiftStdlib 5.7, *) +/// A semantic level to use during regex matching. public struct RegexSemanticLevel: Hashable { internal enum Representation { case graphemeCluster @@ -154,6 +151,38 @@ public struct RegexSemanticLevel: Hashable { } } +@available(SwiftStdlib 5.7, *) +/// A word boundary algorithm to use during regex matching. +public struct RegexWordBoundaryKind: Hashable { + internal enum Representation { + case unicodeLevel1 + case unicodeLevel2 + } + + internal var base: Representation + + /// A word boundary algorithm that implements the "simple word boundary" + /// Unicode recommendation. + /// + /// A simple word boundary is a position in the input between two characters + /// that match `/\w\W/` or `/\W\w/`, or between the start or end of the input + /// and a `\w` character. Word boundaries therefore depend on the option- + /// defined behavior of `\w`. + public static var unicodeLevel1: Self { + .init(base: .unicodeLevel1) + } + + /// A word boundary algorithm that implements the "default word boundary" + /// Unicode recommendation. + /// + /// Default word boundaries use a Unicode algorithm that handles some cases + /// better than simple word boundaries, such as words with internal + /// punctuation, changes in script, and Emoji. + public static var unicodeLevel2: Self { + .init(base: .unicodeLevel2) + } +} + // MARK: - Helper method @available(SwiftStdlib 5.7, *) diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 3d8c4fc2c..897bca8f7 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -228,7 +228,7 @@ class RegexDSLTests: XCTestCase { matchType: Substring.self, ==) { OneOrMore { "abc" - }.ignoringCase(true) + }.ignoresCase(true) } // Multiple options on one component wrap successively, but do not @@ -242,8 +242,8 @@ class RegexDSLTests: XCTestCase { OneOrMore { "abc" } - .ignoringCase(true) - .ignoringCase(false) + .ignoresCase(true) + .ignoresCase(false) } // An option on an outer component doesn't override an option set on an @@ -257,12 +257,36 @@ class RegexDSLTests: XCTestCase { ("abcdeABCdeaBcde", "abcdeABCdeaBcde"), matchType: Substring.self, ==) { OneOrMore { - "abc".ignoringCase(true) + "abc".ignoresCase(true) Optionally("de") } - .ignoringCase(false) + .ignoresCase(false) } +#if os(macOS) + try XCTExpectFailure("Implement level 2 word boundaries") { + try _testDSLCaptures( + ("can't stop won't stop", ("can't stop won't stop", "can't", "won")), + matchType: (Substring, Substring, Substring).self, ==) { + Capture { + OneOrMore(.word) + Anchor.wordBoundary + } + OneOrMore(.any, .reluctantly) + "stop" + " " + + Capture { + OneOrMore(.word) + Anchor.wordBoundary + } + .wordBoundaryKind(.unicodeLevel1) + OneOrMore(.any, .reluctantly) + "stop" + } + } +#endif + try _testDSLCaptures( ("abcdef123", ("abcdef123", "a", "123")), matchType: (Substring, Substring, Substring).self, ==) { @@ -280,6 +304,18 @@ class RegexDSLTests: XCTestCase { } ZeroOrMore(.digit) } + + try _testDSLCaptures( + ("abcdefg", ("abcdefg", "abcdefg")), + ("abcdéfg", ("abcdéfg", "abcd")), + matchType: (Substring, Substring).self, ==) { + Capture { + OneOrMore(.word) + } + .asciiOnlyWordCharacters() + + ZeroOrMore(.any) + } } func testQuantificationBehavior() throws { diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index 8e92c5936..4d9ed4d01 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -1337,7 +1337,7 @@ extension RegexTests { XCTAssertTrue ("cafe".contains(regex)) XCTAssertFalse("CaFe".contains(regex)) - let caseInsensitiveRegex = regex.ignoringCase() + let caseInsensitiveRegex = regex.ignoresCase() XCTAssertTrue("cafe".contains(caseInsensitiveRegex)) XCTAssertTrue("CaFe".contains(caseInsensitiveRegex)) } From 3f161701c9f76a2e18cb3c47ee95453911337b83 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 19 Apr 2022 11:46:59 +0100 Subject: [PATCH 077/133] Don't parse a character property containing a backslash Add backslash to the list of characters we don't consider valid for a character property name. This means that we'll bail when attempting to lex a POSIX character property and instead lex a custom character class. This allows e.g `[:\Q :] \E]` to be lexed as a custom character class. For `\p{...}` this just means we'll emit a truncated invalid property error, which is arguably more inline with what the user was expecting.. I noticed when digging through the ICU source code that it will bail out of parsing a POSIX character property if it encounters one of its known escape sequences (e.g `\a`, `\e`, `\f`, ...). Interestingly this doesn't cover character property escapes e.g `\d`, but it's not clear that is intentional. Given backslash is not a valid character property character anyway, it seems reasonable to broaden this behavior to bail on any backslash. --- .../Regex/Parse/LexicalAnalysis.swift | 8 +++++++ Tests/RegexTests/ParseTests.swift | 21 ++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift index e8b7e9e18..6a61ccdf7 100644 --- a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift +++ b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift @@ -1176,6 +1176,14 @@ extension Source { // character property name anyway, and it's nice not to have diverging // logic for these cases. return true + case "\\": + // An escape sequence, which may include e.g '\Q :] \E'. ICU bails here + // for all its known escape sequences (e.g '\a', '\e' '\f', ...). It + // seems character class escapes e.g '\d' are excluded, however it's not + // clear that is intentional. Let's apply the rule for any escape, as a + // backslash would never be a valid character property name, and we can + // diagnose any invalid escapes when parsing as a character class. + return true default: // We may want to handle other metacharacters here, e.g '{', '(', ')', // as they're not valid character property names. However for now diff --git a/Tests/RegexTests/ParseTests.swift b/Tests/RegexTests/ParseTests.swift index 4043e4ccb..94c134853 100644 --- a/Tests/RegexTests/ParseTests.swift +++ b/Tests/RegexTests/ParseTests.swift @@ -503,6 +503,25 @@ extension RegexTests { parseTest(#"[[:{]]"#, charClass(charClass(":", "{"))) parseTest(#"[[:}:]]"#, charClass(charClass(":", "}", ":"))) + parseTest( + #"[:[:space:]:]"#, + charClass(":", posixProp_m(.binary(.whitespace)), ":") + ) + parseTest( + #"[:a[:space:]b:]"#, + charClass(":", "a", posixProp_m(.binary(.whitespace)), "b", ":") + ) + + // ICU parses a custom character class if it sees any of its known escape + // sequences in a POSIX character property (though it appears to exclude + // character class escapes e.g '\d'). We do so for any escape sequence as + // '\' is not a valid character property character. + parseTest(#"[:\Q:]\E]"#, charClass(":", quote_m(":]"))) + parseTest(#"[:\a:]"#, charClass(":", atom_m(.escaped(.alarm)), ":")) + parseTest(#"[:\d:]"#, charClass(":", atom_m(.escaped(.decimalDigit)), ":")) + parseTest(#"[:\\:]"#, charClass(":", "\\", ":")) + parseTest(#"[:\:]"#, charClass(":", ":")) + parseTest( #"\D\S\W"#, concat( @@ -2319,7 +2338,7 @@ extension RegexTests { diagnosticTest(#"\p{x=y}"#, .unknownProperty(key: "x", value: "y")) diagnosticTest(#"\p{aaa(b)}"#, .unknownProperty(key: nil, value: "aaa(b)")) diagnosticTest("[[:a():]]", .unknownProperty(key: nil, value: "a()")) - diagnosticTest(#"\p{aaa\p{b}}"#, .unknownProperty(key: nil, value: #"aaa\p{b"#)) + diagnosticTest(#"\p{aaa\p{b}}"#, .unknownProperty(key: nil, value: "aaa")) diagnosticTest(#"[[:{:]]"#, .unknownProperty(key: nil, value: "{")) // MARK: Matching options From fa5f2f1c48e96bffc51ebad54fc48f7acc0ab0be Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 19 Apr 2022 13:00:40 +0100 Subject: [PATCH 078/133] Update Regex Syntax document for `[:...:]` changes Clarify that `[:...:]` may be used outside of a custom character class, and discuss the character class disambiguation behavior. --- .../RegexSyntaxRunTimeConstruction.md | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md index cab21288d..3fb0841e3 100644 --- a/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md +++ b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md @@ -392,7 +392,7 @@ For non-Unicode properties, only a value is required. These include: - The special PCRE2 properties `Xan`, `Xps`, `Xsp`, `Xuc`, `Xwd`. - The special Java properties `javaLowerCase`, `javaUpperCase`, `javaWhitespace`, `javaMirrored`. -Note that the internal `PropertyContents` syntax is shared by both the `\p{...}` and POSIX-style `[:...:]` syntax, allowing e.g `[:script=Latin:]` as well as `\p{alnum}`. +Note that the internal `PropertyContents` syntax is shared by both the `\p{...}` and POSIX-style `[:...:]` syntax, allowing e.g `[:script=Latin:]` as well as `\p{alnum}`. Both spellings may be used inside and outside of a custom character class. #### `\K` @@ -534,6 +534,7 @@ These operators have a lower precedence than the implicit union of members, e.g To avoid ambiguity between .NET's subtraction syntax and range syntax, .NET specifies that a subtraction will only be parsed if the right-hand-side is a nested custom character class. We propose following this behavior. +Note that a custom character class may begin with the `:` character, and only becomes a POSIX character property if a closing `:]` is present. For example, `[:a]` is the character class of `:` and `a`. ### Matching options @@ -863,7 +864,23 @@ PCRE supports `\N` meaning "not a newline", however there are engines that treat ### Extended character property syntax -ICU unifies the character property syntax `\p{...}` with the syntax for POSIX character classes `[:...:]`, such that they follow the same internal grammar, which allows referencing any Unicode character property in addition to the POSIX properties. We propose supporting this, though it is a purely additive feature, and therefore should not conflict with regex engines that implement a more limited POSIX syntax. +ICU unifies the character property syntax `\p{...}` with the syntax for POSIX character classes `[:...:]`. This has two effects: + +- They share the same internal grammar, which allows the use of any Unicode character properties in addition to the POSIX properties. +- The POSIX syntax may be used outside of custom character classes, unlike in PCRE and Oniguruma. + +We propose following both of these rules. The former is purely additive, and therefore should not conflict with regex engines that implement a more limited POSIX syntax. The latter does conflict with other engines, but we feel it is much more likely that a user would expect e.g `[:space:]` to be a character property rather than the character class `[:aceps]`. We do however feel that a warning might be warranted in order to avoid confusion. + +### POSIX character property disambiguation + +PCRE, Oniguruma and ICU allow `[:` to be part of a custom character class if a closing `:]` is not present. For example, `[:a]` is the character class of `:` and `a`. However they each have different rules for detecting the closing `:]`: + +- PCRE will scan ahead until it hits either `:]`, `]`, or `[:`. +- Oniguruma will scan ahead until it hits either `:]`, `]`, or the length exceeds 20 characters. +- ICU will scan ahead until it hits a known escape sequence (e.g `\a`, `\e`, `\Q`, ...), or `:]`. Note this excludes character class escapes e.g `\d`. It also excludes `]`, meaning that even `[:a][:]` is parsed as a POSIX character property. + +We propose unifying these behaviors by scanning ahead until we hit either `[`, `]`, `:]`, or `\`. Additionally, we will stop on encountering `}` or a second occurrence of `=`. These fall out the fact that they would be invalid contents of the alternative `\p{...}` syntax. + ### Script properties From 9ccde19174d60a4075d6529a844e0e2a1e204960 Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Tue, 19 Apr 2022 09:11:43 -0700 Subject: [PATCH 079/133] Support obtaining captures by name on `AnyRegexOutput` (#300) Resolves #266. --- Sources/_StringProcessing/ByteCodeGen.swift | 4 ++-- .../_StringProcessing/Engine/MEBuilder.swift | 12 ++++++++++-- .../_StringProcessing/Engine/MECapture.swift | 1 + .../_StringProcessing/Engine/MEProgram.swift | 1 + Sources/_StringProcessing/Executor.swift | 4 +++- .../Regex/AnyRegexOutput.swift | 19 +++++++++++++++++-- Sources/_StringProcessing/Regex/Match.swift | 3 +++ Tests/RegexBuilderTests/RegexDSLTests.swift | 13 +++++++++---- 8 files changed, 46 insertions(+), 11 deletions(-) diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index b6f9b4732..86309bb8a 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -587,11 +587,11 @@ extension Compiler.ByteCodeGen { try emitConcatenationComponent(child) } - case let .capture(_, refId, child): + case let .capture(name, refId, child): options.beginScope() defer { options.endScope() } - let cap = builder.makeCapture(id: refId) + let cap = builder.makeCapture(id: refId, name: name) switch child { case let .matcher(_, m): emitMatcher(m, into: cap) diff --git a/Sources/_StringProcessing/Engine/MEBuilder.swift b/Sources/_StringProcessing/Engine/MEBuilder.swift index 7cf94f6ef..2b38ace0a 100644 --- a/Sources/_StringProcessing/Engine/MEBuilder.swift +++ b/Sources/_StringProcessing/Engine/MEBuilder.swift @@ -45,6 +45,7 @@ extension MEProgram where Input.Element: Hashable { // Symbolic reference resolution var unresolvedReferences: [ReferenceID: [InstructionAddress]] = [:] var referencedCaptureOffsets: [ReferenceID: Int] = [:] + var namedCaptureOffsets: [String: Int] = [:] var captureCount: Int { // We currently deduce the capture count from the capture register number. nextCaptureRegister.rawValue @@ -353,7 +354,8 @@ extension MEProgram.Builder { staticMatcherFunctions: matcherFunctions, registerInfo: regInfo, captureStructure: captureStructure, - referencedCaptureOffsets: referencedCaptureOffsets) + referencedCaptureOffsets: referencedCaptureOffsets, + namedCaptureOffsets: namedCaptureOffsets) } mutating func reset() { self = Self() } @@ -438,7 +440,9 @@ fileprivate extension MEProgram.Builder { // Register helpers extension MEProgram.Builder { - mutating func makeCapture(id: ReferenceID?) -> CaptureRegister { + mutating func makeCapture( + id: ReferenceID?, name: String? + ) -> CaptureRegister { defer { nextCaptureRegister.rawValue += 1 } // Register the capture for later lookup via symbolic references. if let id = id { @@ -446,6 +450,10 @@ extension MEProgram.Builder { captureCount, forKey: id) assert(preexistingValue == nil) } + if let name = name { + // TODO: Reject duplicate capture names unless `(?J)`? + namedCaptureOffsets.updateValue(captureCount, forKey: name) + } return nextCaptureRegister } diff --git a/Sources/_StringProcessing/Engine/MECapture.swift b/Sources/_StringProcessing/Engine/MECapture.swift index 390af7d66..807598637 100644 --- a/Sources/_StringProcessing/Engine/MECapture.swift +++ b/Sources/_StringProcessing/Engine/MECapture.swift @@ -145,6 +145,7 @@ extension Processor._StoredCapture: CustomStringConvertible { struct CaptureList { var values: Array._StoredCapture> var referencedCaptureOffsets: [ReferenceID: Int] + var namedCaptureOffsets: [String: Int] // func extract(from s: String) -> Array> { // caps.map { $0.map { s[$0] } } diff --git a/Sources/_StringProcessing/Engine/MEProgram.swift b/Sources/_StringProcessing/Engine/MEProgram.swift index b0f2e6a79..0bfa0ecba 100644 --- a/Sources/_StringProcessing/Engine/MEProgram.swift +++ b/Sources/_StringProcessing/Engine/MEProgram.swift @@ -36,6 +36,7 @@ struct MEProgram where Input.Element: Equatable { let captureStructure: CaptureStructure let referencedCaptureOffsets: [ReferenceID: Int] + let namedCaptureOffsets: [String: Int] } extension MEProgram: CustomStringConvertible { diff --git a/Sources/_StringProcessing/Executor.swift b/Sources/_StringProcessing/Executor.swift index c7d4527a5..6ebb93f5c 100644 --- a/Sources/_StringProcessing/Executor.swift +++ b/Sources/_StringProcessing/Executor.swift @@ -37,7 +37,8 @@ struct Executor { let capList = CaptureList( values: cpu.storedCaptures, - referencedCaptureOffsets: engine.program.referencedCaptureOffsets) + referencedCaptureOffsets: engine.program.referencedCaptureOffsets, + namedCaptureOffsets: engine.program.namedCaptureOffsets) let capStruct = engine.program.captureStructure let range = inputRange.lowerBound.. Substring { input[range] } + + public subscript(name: String) -> AnyRegexOutput.Element? { + namedCaptureOffsets[name].map { self[$0 + 1] } + } } /// A type-erased regex output @available(SwiftStdlib 5.7, *) public struct AnyRegexOutput { let input: String + let namedCaptureOffsets: [String: Int] fileprivate let _elements: [ElementRepresentation] /// The underlying representation of the element of a type-erased regex @@ -94,9 +99,12 @@ extension AnyRegexOutput { @available(SwiftStdlib 5.7, *) extension AnyRegexOutput { internal init( - input: String, elements: C + input: String, namedCaptureOffsets: [String: Int], elements: C ) where C.Element == StructuredCapture { - self.init(input: input, _elements: elements.map(ElementRepresentation.init)) + self.init( + input: input, + namedCaptureOffsets: namedCaptureOffsets, + _elements: elements.map(ElementRepresentation.init)) } } @@ -170,6 +178,13 @@ extension AnyRegexOutput: RandomAccessCollection { } } +@available(SwiftStdlib 5.7, *) +extension AnyRegexOutput { + public subscript(name: String) -> Element? { + namedCaptureOffsets[name].map { self[$0 + 1] } + } +} + @available(SwiftStdlib 5.7, *) extension Regex.Match where Output == AnyRegexOutput { /// Creates a type-erased regex match from an existing match. diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index a86899041..4b2f117e4 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -26,6 +26,8 @@ extension Regex { let referencedCaptureOffsets: [ReferenceID: Int] + let namedCaptureOffsets: [String: Int] + let value: Any? } } @@ -40,6 +42,7 @@ extension Regex.Match { storedCapture: StoredCapture(range: range, value: nil)) let output = AnyRegexOutput( input: input, + namedCaptureOffsets: namedCaptureOffsets, elements: [wholeMatchAsCapture] + rawCaptures) return output as! Output } else if Output.self == Substring.self { diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 897bca8f7..58f847f32 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -689,7 +689,9 @@ class RegexDSLTests: XCTestCase { } do { let regex = try Regex( - compiling: #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#) + compiling: #""" + (?[0-9A-F]+)(?:\.\.(?[0-9A-F]+))?\s+;\s+(?\w+).* + """#) let line = """ A6F0..A6F1 ; Extend # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM \ COMBINING MARK TUKWENTIS @@ -699,13 +701,16 @@ class RegexDSLTests: XCTestCase { let output = match.output XCTAssertEqual(output[0].substring, line[...]) XCTAssertTrue(output[1].substring == "A6F0") + XCTAssertTrue(output["lower"]?.substring == "A6F0") XCTAssertTrue(output[2].substring == "A6F1") + XCTAssertTrue(output["upper"]?.substring == "A6F1") XCTAssertTrue(output[3].substring == "Extend") + XCTAssertTrue(output["desc"]?.substring == "Extend") let typedOutput = try XCTUnwrap(output.as( - (Substring, Substring, Substring?, Substring).self)) + (Substring, lower: Substring, upper: Substring?, Substring).self)) XCTAssertEqual(typedOutput.0, line[...]) - XCTAssertTrue(typedOutput.1 == "A6F0") - XCTAssertTrue(typedOutput.2 == "A6F1") + XCTAssertTrue(typedOutput.lower == "A6F0") + XCTAssertTrue(typedOutput.upper == "A6F1") XCTAssertTrue(typedOutput.3 == "Extend") } } From 182da3bb462055f50e9b67aae626d43fe70025a6 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 19 Apr 2022 11:33:11 -0500 Subject: [PATCH 080/133] Untangle `_RegexParser` from `RegexBuilder` (#299) This makes the changes necessary for _RegexParser to be imported as an implementation-only dependency. The change provides _StringProcessing wrappers for all `AST` types that need to be publicly visible via SPI, and a DSLTree.Node wrapper for internal conformance to _TreeNode. Co-authored-by: Richard Wei --- Sources/RegexBuilder/Anchor.swift | 37 +- Sources/RegexBuilder/CharacterClass.swift | 61 +-- Sources/RegexBuilder/DSL.swift | 12 +- Sources/RegexBuilder/Variadics.swift | 45 ++- .../VariadicsGenerator.swift | 5 +- Sources/_StringProcessing/ByteCodeGen.swift | 20 +- .../_StringProcessing/ConsumerInterface.swift | 2 +- .../_StringProcessing/PrintAsPattern.swift | 17 +- .../Regex/ASTConversion.swift | 20 +- .../Regex/DSLConsumers.swift | 3 +- Sources/_StringProcessing/Regex/DSLTree.swift | 373 ++++++++++++++---- Sources/_StringProcessing/Regex/Options.swift | 2 +- .../_CharacterClassModel.swift | 26 +- Tests/RegexBuilderTests/CustomTests.swift | 15 +- 14 files changed, 399 insertions(+), 239 deletions(-) diff --git a/Sources/RegexBuilder/Anchor.swift b/Sources/RegexBuilder/Anchor.swift index 55b554aea..e8cd4ac54 100644 --- a/Sources/RegexBuilder/Anchor.swift +++ b/Sources/RegexBuilder/Anchor.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser @_spi(RegexBuilder) import _StringProcessing @available(SwiftStdlib 5.7, *) @@ -31,34 +31,21 @@ public struct Anchor { @available(SwiftStdlib 5.7, *) extension Anchor: RegexComponent { - var astAssertion: AST.Atom.AssertionKind { - if !isInverted { - switch kind { - case .startOfSubject: return .startOfSubject - case .endOfSubjectBeforeNewline: return .endOfSubjectBeforeNewline - case .endOfSubject: return .endOfSubject - case .firstMatchingPositionInSubject: return .firstMatchingPositionInSubject - case .textSegmentBoundary: return .textSegment - case .startOfLine: return .startOfLine - case .endOfLine: return .endOfLine - case .wordBoundary: return .wordBoundary - } - } else { - switch kind { - case .startOfSubject: fatalError("Not yet supported") - case .endOfSubjectBeforeNewline: fatalError("Not yet supported") - case .endOfSubject: fatalError("Not yet supported") - case .firstMatchingPositionInSubject: fatalError("Not yet supported") - case .textSegmentBoundary: return .notTextSegment - case .startOfLine: fatalError("Not yet supported") - case .endOfLine: fatalError("Not yet supported") - case .wordBoundary: return .notWordBoundary - } + var baseAssertion: DSLTree._AST.AssertionKind { + switch kind { + case .startOfSubject: return .startOfSubject(isInverted) + case .endOfSubjectBeforeNewline: return .endOfSubjectBeforeNewline(isInverted) + case .endOfSubject: return .endOfSubject(isInverted) + case .firstMatchingPositionInSubject: return .firstMatchingPositionInSubject(isInverted) + case .textSegmentBoundary: return .textSegmentBoundary(isInverted) + case .startOfLine: return .startOfLine(isInverted) + case .endOfLine: return .endOfLine(isInverted) + case .wordBoundary: return .wordBoundary(isInverted) } } public var regex: Regex { - Regex(node: .atom(.assertion(astAssertion))) + Regex(node: .atom(.assertion(baseAssertion))) } } diff --git a/Sources/RegexBuilder/CharacterClass.swift b/Sources/RegexBuilder/CharacterClass.swift index d163c336b..0087d734a 100644 --- a/Sources/RegexBuilder/CharacterClass.swift +++ b/Sources/RegexBuilder/CharacterClass.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser @_spi(RegexBuilder) import _StringProcessing @available(SwiftStdlib 5.7, *) @@ -21,19 +21,10 @@ public struct CharacterClass { } init(unconverted model: _CharacterClassModel) { - // FIXME: Implement in DSLTree instead of wrapping an AST atom - switch model.makeAST() { - case .atom(let atom): - self.ccc = .init(members: [.atom(.unconverted(atom))]) - default: - fatalError("Unsupported _CharacterClassModel") + guard let ccc = model.makeDSLTreeCharacterClass() else { + fatalError("Unsupported character class") } - } - - init(property: AST.Atom.CharacterProperty) { - // FIXME: Implement in DSLTree instead of wrapping an AST atom - let astAtom = AST.Atom(.property(property), .fake) - self.ccc = .init(members: [.atom(.unconverted(astAtom))]) + self.ccc = ccc } } @@ -119,11 +110,7 @@ extension RegexComponent where Self == CharacterClass { @available(SwiftStdlib 5.7, *) extension CharacterClass { public static func generalCategory(_ category: Unicode.GeneralCategory) -> CharacterClass { - guard let extendedCategory = category.extendedGeneralCategory else { - fatalError("Unexpected general category") - } - return CharacterClass(property: - .init(.generalCategory(extendedCategory), isInverted: false, isPOSIX: false)) + return CharacterClass(.generalCategory(category)) } } @@ -144,44 +131,6 @@ public func ...(lhs: UnicodeScalar, rhs: UnicodeScalar) -> CharacterClass { return CharacterClass(ccc) } -extension Unicode.GeneralCategory { - var extendedGeneralCategory: Unicode.ExtendedGeneralCategory? { - switch self { - case .uppercaseLetter: return .uppercaseLetter - case .lowercaseLetter: return .lowercaseLetter - case .titlecaseLetter: return .titlecaseLetter - case .modifierLetter: return .modifierLetter - case .otherLetter: return .otherLetter - case .nonspacingMark: return .nonspacingMark - case .spacingMark: return .spacingMark - case .enclosingMark: return .enclosingMark - case .decimalNumber: return .decimalNumber - case .letterNumber: return .letterNumber - case .otherNumber: return .otherNumber - case .connectorPunctuation: return .connectorPunctuation - case .dashPunctuation: return .dashPunctuation - case .openPunctuation: return .openPunctuation - case .closePunctuation: return .closePunctuation - case .initialPunctuation: return .initialPunctuation - case .finalPunctuation: return .finalPunctuation - case .otherPunctuation: return .otherPunctuation - case .mathSymbol: return .mathSymbol - case .currencySymbol: return .currencySymbol - case .modifierSymbol: return .modifierSymbol - case .otherSymbol: return .otherSymbol - case .spaceSeparator: return .spaceSeparator - case .lineSeparator: return .lineSeparator - case .paragraphSeparator: return .paragraphSeparator - case .control: return .control - case .format: return .format - case .surrogate: return .surrogate - case .privateUse: return .privateUse - case .unassigned: return .unassigned - @unknown default: return nil - } - } -} - // MARK: - Set algebra methods @available(SwiftStdlib 5.7, *) diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 86ec0bee5..97bc35154 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser @_spi(RegexBuilder) import _StringProcessing @available(SwiftStdlib 5.7, *) @@ -105,7 +105,7 @@ public struct QuantificationBehavior { var kind: Kind - internal var astKind: AST.Quantification.Kind { + internal var astKind: DSLTree._AST.QuantificationKind { switch kind { case .eagerly: return .eager case .reluctantly: return .reluctant @@ -136,13 +136,13 @@ extension DSLTree.Node { return .quantification(.oneOrMore, kind, node) case _ where range.count == 1: // ..<1 or ...0 or any range with count == 1 // Note: `behavior` is ignored in this case - return .quantification(.exactly(.init(faking: range.lowerBound)), .default, node) + return .quantification(.exactly(range.lowerBound), .default, node) case (0, _): // 0.. 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -720,7 +719,7 @@ extension Repeat { ) where RegexOutput == Substring { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) @@ -835,7 +834,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -845,7 +844,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) @@ -958,7 +957,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -968,7 +967,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1081,7 +1080,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1091,7 +1090,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1204,7 +1203,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1214,7 +1213,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1327,7 +1326,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1337,7 +1336,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1450,7 +1449,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1460,7 +1459,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1573,7 +1572,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1583,7 +1582,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1696,7 +1695,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1706,7 +1705,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1819,7 +1818,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1829,7 +1828,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1942,7 +1941,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } @available(SwiftStdlib 5.7, *) @@ -1952,7 +1951,7 @@ extension Repeat { ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } @available(SwiftStdlib 5.7, *) diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index d1cb41810..50f09700e 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -121,7 +121,6 @@ struct VariadicsGenerator: ParsableCommand { // BEGIN AUTO-GENERATED CONTENT - import _RegexParser @_spi(RegexBuilder) import _StringProcessing @@ -490,7 +489,7 @@ struct VariadicsGenerator: ParsableCommand { ) \(params.whereClauseForInit) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } \(defaultAvailableAttr) @@ -501,7 +500,7 @@ struct VariadicsGenerator: ParsableCommand { ) \(params.whereClauseForInit) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } \(defaultAvailableAttr) diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index 86309bb8a..621538ebe 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -26,22 +26,22 @@ extension Compiler.ByteCodeGen { try emitScalar(s) case let .assertion(kind): - try emitAssertion(kind) + try emitAssertion(kind.ast) case let .backreference(ref): - try emitBackreference(ref) + try emitBackreference(ref.ast) case let .symbolicReference(id): builder.buildUnresolvedReference(id: id) case let .changeMatchingOptions(optionSequence): - options.apply(optionSequence) + options.apply(optionSequence.ast) case let .unconverted(astAtom): - if let consumer = try astAtom.generateConsumer(options) { + if let consumer = try astAtom.ast.generateConsumer(options) { builder.buildConsume(by: consumer) } else { - throw Unsupported("\(astAtom._patternBase)") + throw Unsupported("\(astAtom.ast._patternBase)") } } } @@ -370,9 +370,9 @@ extension Compiler.ByteCodeGen { let updatedKind: AST.Quantification.Kind switch kind { case .explicit(let kind): - updatedKind = kind + updatedKind = kind.ast case .syntax(let kind): - updatedKind = kind.applying(options) + updatedKind = kind.ast.applying(options) case .default: updatedKind = options.isReluctantByDefault ? .reluctant @@ -604,13 +604,13 @@ extension Compiler.ByteCodeGen { } case let .nonCapturingGroup(kind, child): - try emitNoncapturingGroup(kind, child) + try emitNoncapturingGroup(kind.ast, child) case .conditional: throw Unsupported("Conditionals") case let .quantification(amt, kind, child): - try emitQuantification(amt, kind, child) + try emitQuantification(amt.ast, kind, child) case let .customCharacterClass(ccc): if ccc.containsAny { @@ -646,7 +646,7 @@ extension Compiler.ByteCodeGen { } case let .regexLiteral(l): - try emitNode(l.dslTreeNode) + try emitNode(l.ast.dslTreeNode) case let .convertedRegexLiteral(n, _): try emitNode(n) diff --git a/Sources/_StringProcessing/ConsumerInterface.swift b/Sources/_StringProcessing/ConsumerInterface.swift index f77cd322f..356b7cc4b 100644 --- a/Sources/_StringProcessing/ConsumerInterface.swift +++ b/Sources/_StringProcessing/ConsumerInterface.swift @@ -105,7 +105,7 @@ extension DSLTree.Atom { return nil case let .unconverted(a): - return try a.generateConsumer(opts) + return try a.ast.generateConsumer(opts) } } diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index 4d135898b..91626eb5c 100644 --- a/Sources/_StringProcessing/PrintAsPattern.swift +++ b/Sources/_StringProcessing/PrintAsPattern.swift @@ -68,7 +68,7 @@ extension PrettyPrinter { private mutating func printAsPattern( convertedFromAST node: DSLTree.Node ) { - if patternBackoff(node) { + if patternBackoff(DSLTree._Tree(node)) { printBackoff(node) return } @@ -90,7 +90,7 @@ extension PrettyPrinter { } case let .nonCapturingGroup(kind, child): - let kind = kind._patternBase + let kind = kind.ast._patternBase printBlock("Group(\(kind))") { printer in printer.printAsPattern(convertedFromAST: child) } @@ -108,8 +108,8 @@ extension PrettyPrinter { print("/* TODO: conditional */") case let .quantification(amount, kind, child): - let amount = amount._patternBase - let kind = kind._patternBase + let amount = amount.ast._patternBase + let kind = (kind.ast ?? .eager)._patternBase printBlock("\(amount)(\(kind))") { printer in printer.printAsPattern(convertedFromAST: child) } @@ -129,7 +129,7 @@ extension PrettyPrinter { case let .unconverted(a): // TODO: is this always right? // TODO: Convert built-in character classes - print(a._patternBase) + print(a.ast._patternBase) case .assertion: print("/* TODO: assertions */") @@ -400,11 +400,6 @@ extension AST.Quantification.Kind { extension DSLTree.QuantificationKind { var _patternBase: String { - switch self { - case .explicit(let kind), .syntax(let kind): - return kind._patternBase - case .default: - return ".eager" - } + (ast ?? .eager)._patternBase } } diff --git a/Sources/_StringProcessing/Regex/ASTConversion.swift b/Sources/_StringProcessing/Regex/ASTConversion.swift index 8acbd3b1b..ef98a7b8f 100644 --- a/Sources/_StringProcessing/Regex/ASTConversion.swift +++ b/Sources/_StringProcessing/Regex/ASTConversion.swift @@ -40,7 +40,7 @@ extension AST.Node { // TODO: Should we do this for the // single-concatenation child too, or should? // we wrap _that_? - return .convertedRegexLiteral(node, self) + return .convertedRegexLiteral(node, .init(ast: self)) } // Convert the top-level node without wrapping @@ -111,19 +111,19 @@ extension AST.Node { case .balancedCapture: throw Unsupported("TODO: balanced captures") default: - return .nonCapturingGroup(v.kind.value, child) + return .nonCapturingGroup(.init(ast: v.kind.value), child) } case let .conditional(v): let trueBranch = v.trueBranch.dslTreeNode let falseBranch = v.falseBranch.dslTreeNode return .conditional( - v.condition.kind, trueBranch, falseBranch) + .init(ast: v.condition.kind), trueBranch, falseBranch) case let .quantification(v): let child = v.child.dslTreeNode return .quantification( - v.amount.value, .syntax(v.kind.value), child) + .init(ast: v.amount.value), .syntax(.init(ast: v.kind.value)), child) case let .quote(v): return .quotedLiteral(v.literal) @@ -140,9 +140,9 @@ extension AST.Node { case .empty(_): return .empty - case let .absentFunction(a): + case let .absentFunction(abs): // TODO: What should this map to? - return .absentFunction(a) + return .absentFunction(.init(ast: abs)) } } @@ -202,20 +202,20 @@ extension AST.CustomCharacterClass { extension AST.Atom { var dslTreeAtom: DSLTree.Atom { if let kind = assertionKind { - return .assertion(kind) + return .assertion(.init(ast: kind)) } switch self.kind { case let .char(c): return .char(c) case let .scalar(s): return .scalar(s) case .any: return .any - case let .backreference(r): return .backreference(r) - case let .changeMatchingOptions(seq): return .changeMatchingOptions(seq) + case let .backreference(r): return .backreference(.init(ast: r)) + case let .changeMatchingOptions(seq): return .changeMatchingOptions(.init(ast: seq)) case .escaped(let c) where c.scalarValue != nil: return .scalar(c.scalarValue!) - default: return .unconverted(self) + default: return .unconverted(.init(ast: self)) } } } diff --git a/Sources/_StringProcessing/Regex/DSLConsumers.swift b/Sources/_StringProcessing/Regex/DSLConsumers.swift index ea46c789b..eb8ace8d3 100644 --- a/Sources/_StringProcessing/Regex/DSLConsumers.swift +++ b/Sources/_StringProcessing/Regex/DSLConsumers.swift @@ -21,8 +21,7 @@ public protocol CustomMatchingRegexComponent: RegexComponent { @available(SwiftStdlib 5.7, *) extension CustomMatchingRegexComponent { public var regex: Regex { - - let node: DSLTree.Node = .matcher(.init(RegexOutput.self), { input, index, bounds in + let node: DSLTree.Node = .matcher(RegexOutput.self, { input, index, bounds in try match(input, startingAt: index, in: bounds) }) return Regex(node: node) diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index 51f5ea36f..ce5beeaca 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -24,7 +24,7 @@ public struct DSLTree { extension DSLTree { @_spi(RegexBuilder) - public indirect enum Node: _TreeNode { + public indirect enum Node { /// Try to match each node in order /// /// ... | ... | ... @@ -42,7 +42,7 @@ extension DSLTree { name: String? = nil, reference: ReferenceID? = nil, Node) /// Match a (non-capturing) subpattern / group - case nonCapturingGroup(AST.Group.Kind, Node) + case nonCapturingGroup(_AST.GroupKind, Node) // TODO: Consider splitting off grouped conditions, or have // our own kind @@ -52,10 +52,10 @@ extension DSLTree { /// (?(cond) true-branch | false-branch) /// case conditional( - AST.Conditional.Condition.Kind, Node, Node) + _AST.ConditionKind, Node, Node) case quantification( - AST.Quantification.Amount, + _AST.QuantificationAmount, QuantificationKind, Node) @@ -74,19 +74,19 @@ extension DSLTree { case quotedLiteral(String) /// An embedded literal - case regexLiteral(AST.Node) + case regexLiteral(_AST.ASTNode) // TODO: What should we do here? /// /// TODO: Consider splitting off expression functions, or have our own kind - case absentFunction(AST.AbsentFunction) + case absentFunction(_AST.AbsentFunction) // MARK: - Tree conversions /// The target of AST conversion. /// /// Keeps original AST around for rich syntactic and source information - case convertedRegexLiteral(Node, AST.Node) + case convertedRegexLiteral(Node, _AST.ASTNode) // MARK: - Extensibility points @@ -95,7 +95,7 @@ extension DSLTree { case consumer(_ConsumerInterface) - case matcher(AnyType, _MatcherInterface) + case matcher(Any.Type, _MatcherInterface) // TODO: Would this just boil down to a consumer? case characterPredicate(_CharacterPredicateInterface) @@ -108,9 +108,17 @@ extension DSLTree { /// The default quantification kind, as set by options. case `default` /// An explicitly chosen kind, overriding any options. - case explicit(AST.Quantification.Kind) + case explicit(_AST.QuantificationKind) /// A kind set via syntax, which can be affected by options. - case syntax(AST.Quantification.Kind) + case syntax(_AST.QuantificationKind) + + var ast: AST.Quantification.Kind? { + switch self { + case .default: return nil + case .explicit(let kind), .syntax(let kind): + return kind.ast + } + } } @_spi(RegexBuilder) @@ -134,6 +142,12 @@ extension DSLTree { self.isInverted = isInverted } + public static func generalCategory(_ category: Unicode.GeneralCategory) -> Self { + let property = AST.Atom.CharacterProperty(.generalCategory(category.extendedGeneralCategory!), isInverted: false, isPOSIX: false) + let astAtom = AST.Atom(.property(property), .fake) + return .init(members: [.atom(.unconverted(.init(ast: astAtom)))]) + } + public var inverted: CustomCharacterClass { var result = self result.isInverted.toggle() @@ -162,13 +176,51 @@ extension DSLTree { case scalar(Unicode.Scalar) case any - case assertion(AST.Atom.AssertionKind) - case backreference(AST.Reference) + case assertion(_AST.AssertionKind) + case backreference(_AST.Reference) case symbolicReference(ReferenceID) - case changeMatchingOptions(AST.MatchingOptionSequence) + case changeMatchingOptions(_AST.MatchingOptionSequence) + + case unconverted(_AST.Atom) + } +} - case unconverted(AST.Atom) +extension Unicode.GeneralCategory { + var extendedGeneralCategory: Unicode.ExtendedGeneralCategory? { + switch self { + case .uppercaseLetter: return .uppercaseLetter + case .lowercaseLetter: return .lowercaseLetter + case .titlecaseLetter: return .titlecaseLetter + case .modifierLetter: return .modifierLetter + case .otherLetter: return .otherLetter + case .nonspacingMark: return .nonspacingMark + case .spacingMark: return .spacingMark + case .enclosingMark: return .enclosingMark + case .decimalNumber: return .decimalNumber + case .letterNumber: return .letterNumber + case .otherNumber: return .otherNumber + case .connectorPunctuation: return .connectorPunctuation + case .dashPunctuation: return .dashPunctuation + case .openPunctuation: return .openPunctuation + case .closePunctuation: return .closePunctuation + case .initialPunctuation: return .initialPunctuation + case .finalPunctuation: return .finalPunctuation + case .otherPunctuation: return .otherPunctuation + case .mathSymbol: return .mathSymbol + case .currencySymbol: return .currencySymbol + case .modifierSymbol: return .modifierSymbol + case .otherSymbol: return .otherSymbol + case .spaceSeparator: return .spaceSeparator + case .lineSeparator: return .lineSeparator + case .paragraphSeparator: return .paragraphSeparator + case .control: return .control + case .format: return .format + case .surrogate: return .surrogate + case .privateUse: return .privateUse + case .unassigned: return .unassigned + @unknown default: return nil + } } } @@ -226,8 +278,8 @@ extension DSLTree.Node { .customCharacterClass, .atom: return [] - case let .absentFunction(a): - return a.children.map(\.dslTreeNode) + case let .absentFunction(abs): + return abs.ast.children.map(\.dslTreeNode) } } } @@ -235,8 +287,8 @@ extension DSLTree.Node { extension DSLTree.Node { var astNode: AST.Node? { switch self { - case let .regexLiteral(ast): return ast - case let .convertedRegexLiteral(_, ast): return ast + case let .regexLiteral(literal): return literal.ast + case let .convertedRegexLiteral(_, literal): return literal.ast default: return nil } } @@ -280,9 +332,9 @@ extension DSLTree.Node { case .capture: return true case let .regexLiteral(re): - return re.hasCapture + return re.ast.hasCapture case let .convertedRegexLiteral(n, re): - assert(n.hasCapture == re.hasCapture) + assert(n.hasCapture == re.ast.hasCapture) return n.hasCapture default: @@ -295,70 +347,15 @@ extension DSLTree { var captureStructure: CaptureStructure { // TODO: nesting var constructor = CaptureStructure.Constructor(.flatten) - return root._captureStructure(&constructor) + return _Tree(root)._captureStructure(&constructor) } } extension DSLTree.Node { - @_spi(RegexBuilder) - public func _captureStructure( - _ constructor: inout CaptureStructure.Constructor - ) -> CaptureStructure { - switch self { - case let .orderedChoice(children): - return constructor.alternating(children) - - case let .concatenation(children): - return constructor.concatenating(children) - - case let .capture(name, _, child): - if let type = child.valueCaptureType { - return constructor.capturing( - name: name, child, withType: type) - } - return constructor.capturing(name: name, child) - - case let .nonCapturingGroup(kind, child): - assert(!kind.isCapturing) - return constructor.grouping(child, as: kind) - - case let .conditional(cond, trueBranch, falseBranch): - return constructor.condition( - cond, - trueBranch: trueBranch, - falseBranch: falseBranch) - - case let .quantification(amount, _, child): - return constructor.quantifying( - child, amount: amount) - - case let .regexLiteral(re): - // TODO: Force a re-nesting? - return re._captureStructure(&constructor) - - case let .absentFunction(abs): - return constructor.absent(abs.kind) - - case let .convertedRegexLiteral(n, _): - // TODO: Switch nesting strategy? - return n._captureStructure(&constructor) - - case .matcher: - return .empty - - case .transform(_, let child): - return child._captureStructure(&constructor) - - case .customCharacterClass, .atom, .trivia, .empty, - .quotedLiteral, .consumer, .characterPredicate: - return .empty - } - } - /// For typed capture-producing nodes, the type produced. var valueCaptureType: AnyType? { switch self { case let .matcher(t, _): - return t + return AnyType(t) case let .transform(t, _): return AnyType(t.resultType) default: return nil @@ -455,3 +452,225 @@ public struct CaptureTransform: Hashable, CustomStringConvertible { "" } } + +// MARK: AST wrapper types +// +// These wrapper types are required because even @_spi-marked public APIs can't +// include symbols from implementation-only dependencies. + +extension DSLTree { + /// Presents a wrapped version of `DSLTree.Node` that can provide an internal + /// `_TreeNode` conformance. + struct _Tree: _TreeNode { + var node: DSLTree.Node + + init(_ node: DSLTree.Node) { + self.node = node + } + + var children: [_Tree]? { + switch node { + + case let .orderedChoice(v): return v.map(_Tree.init) + case let .concatenation(v): return v.map(_Tree.init) + + case let .convertedRegexLiteral(n, _): + // Treat this transparently + return _Tree(n).children + + case let .capture(_, _, n): return [_Tree(n)] + case let .nonCapturingGroup(_, n): return [_Tree(n)] + case let .transform(_, n): return [_Tree(n)] + case let .quantification(_, _, n): return [_Tree(n)] + + case let .conditional(_, t, f): return [_Tree(t), _Tree(f)] + + case .trivia, .empty, .quotedLiteral, .regexLiteral, + .consumer, .matcher, .characterPredicate, + .customCharacterClass, .atom: + return [] + + case let .absentFunction(abs): + return abs.ast.children.map(\.dslTreeNode).map(_Tree.init) + } + } + + func _captureStructure( + _ constructor: inout CaptureStructure.Constructor + ) -> CaptureStructure { + switch node { + case let .orderedChoice(children): + return constructor.alternating(children.map(_Tree.init)) + + case let .concatenation(children): + return constructor.concatenating(children.map(_Tree.init)) + + case let .capture(name, _, child): + if let type = child.valueCaptureType { + return constructor.capturing( + name: name, _Tree(child), withType: type) + } + return constructor.capturing(name: name, _Tree(child)) + + case let .nonCapturingGroup(kind, child): + assert(!kind.ast.isCapturing) + return constructor.grouping(_Tree(child), as: kind.ast) + + case let .conditional(cond, trueBranch, falseBranch): + return constructor.condition( + cond.ast, + trueBranch: _Tree(trueBranch), + falseBranch: _Tree(falseBranch)) + + case let .quantification(amount, _, child): + return constructor.quantifying( + Self(child), amount: amount.ast) + + case let .regexLiteral(re): + // TODO: Force a re-nesting? + return re.ast._captureStructure(&constructor) + + case let .absentFunction(abs): + return constructor.absent(abs.ast.kind) + + case let .convertedRegexLiteral(n, _): + // TODO: Switch nesting strategy? + return Self(n)._captureStructure(&constructor) + + case .matcher: + return .empty + + case .transform(_, let child): + return Self(child)._captureStructure(&constructor) + + case .customCharacterClass, .atom, .trivia, .empty, + .quotedLiteral, .consumer, .characterPredicate: + return .empty + } + } + } + + @_spi(RegexBuilder) + public enum _AST { + @_spi(RegexBuilder) + public struct GroupKind { + internal var ast: AST.Group.Kind + + public static var atomicNonCapturing: Self { + .init(ast: .atomicNonCapturing) + } + public static var lookahead: Self { + .init(ast: .lookahead) + } + public static var negativeLookahead: Self { + .init(ast: .negativeLookahead) + } + } + + @_spi(RegexBuilder) + public struct ConditionKind { + internal var ast: AST.Conditional.Condition.Kind + } + + @_spi(RegexBuilder) + public struct QuantificationKind { + internal var ast: AST.Quantification.Kind + + public static var eager: Self { + .init(ast: .eager) + } + public static var reluctant: Self { + .init(ast: .reluctant) + } + public static var possessive: Self { + .init(ast: .possessive) + } + } + + @_spi(RegexBuilder) + public struct QuantificationAmount { + internal var ast: AST.Quantification.Amount + + public static var zeroOrMore: Self { + .init(ast: .zeroOrMore) + } + public static var oneOrMore: Self { + .init(ast: .oneOrMore) + } + public static var zeroOrOne: Self { + .init(ast: .zeroOrOne) + } + public static func exactly(_ n: Int) -> Self { + .init(ast: .exactly(.init(faking: n))) + } + public static func nOrMore(_ n: Int) -> Self { + .init(ast: .nOrMore(.init(faking: n))) + } + public static func upToN(_ n: Int) -> Self { + .init(ast: .upToN(.init(faking: n))) + } + public static func range(_ lower: Int, _ upper: Int) -> Self { + .init(ast: .range(.init(faking: lower), .init(faking: upper))) + } + } + + @_spi(RegexBuilder) + public struct ASTNode { + internal var ast: AST.Node + } + + @_spi(RegexBuilder) + public struct AbsentFunction { + internal var ast: AST.AbsentFunction + } + + @_spi(RegexBuilder) + public struct AssertionKind { + internal var ast: AST.Atom.AssertionKind + + public static func startOfSubject(_ inverted: Bool = false) -> Self { + .init(ast: .startOfSubject) + } + public static func endOfSubjectBeforeNewline(_ inverted: Bool = false) -> Self { + .init(ast: .endOfSubjectBeforeNewline) + } + public static func endOfSubject(_ inverted: Bool = false) -> Self { + .init(ast: .endOfSubject) + } + public static func firstMatchingPositionInSubject(_ inverted: Bool = false) -> Self { + .init(ast: .firstMatchingPositionInSubject) + } + public static func textSegmentBoundary(_ inverted: Bool = false) -> Self { + inverted + ? .init(ast: .notTextSegment) + : .init(ast: .textSegment) + } + public static func startOfLine(_ inverted: Bool = false) -> Self { + .init(ast: .startOfLine) + } + public static func endOfLine(_ inverted: Bool = false) -> Self { + .init(ast: .endOfLine) + } + public static func wordBoundary(_ inverted: Bool = false) -> Self { + inverted + ? .init(ast: .notWordBoundary) + : .init(ast: .wordBoundary) + } + } + + @_spi(RegexBuilder) + public struct Reference { + internal var ast: AST.Reference + } + + @_spi(RegexBuilder) + public struct MatchingOptionSequence { + internal var ast: AST.MatchingOptionSequence + } + + @_spi(RegexBuilder) + public struct Atom { + internal var ast: AST.Atom + } + } +} diff --git a/Sources/_StringProcessing/Regex/Options.swift b/Sources/_StringProcessing/Regex/Options.swift index 623589b54..a93421f4f 100644 --- a/Sources/_StringProcessing/Regex/Options.swift +++ b/Sources/_StringProcessing/Regex/Options.swift @@ -195,6 +195,6 @@ extension RegexComponent { ? AST.MatchingOptionSequence(adding: [.init(option, location: .fake)]) : AST.MatchingOptionSequence(removing: [.init(option, location: .fake)]) return Regex(node: .nonCapturingGroup( - .changeMatchingOptions(sequence), regex.root)) + .init(ast: .changeMatchingOptions(sequence)), regex.root)) } } diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index c9762f00e..2debcda9d 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -28,7 +28,7 @@ public struct _CharacterClassModel: Hashable { var isInverted: Bool = false // TODO: Split out builtin character classes into their own type? - public enum Representation: Hashable { + public enum Representation: Hashable { /// Any character case any /// Any grapheme cluster @@ -52,10 +52,14 @@ public struct _CharacterClassModel: Hashable { case custom([CharacterSetComponent]) } - public typealias SetOperator = AST.CustomCharacterClass.SetOp + public enum SetOperator: Hashable { + case subtraction + case intersection + case symmetricDifference + } /// A binary set operation that forms a character class component. - public struct SetOperation: Hashable { + public struct SetOperation: Hashable { var lhs: CharacterSetComponent var op: SetOperator var rhs: CharacterSetComponent @@ -72,7 +76,7 @@ public struct _CharacterClassModel: Hashable { } } - public enum CharacterSetComponent: Hashable { + public enum CharacterSetComponent: Hashable { case character(Character) case range(ClosedRange) @@ -294,7 +298,17 @@ extension _CharacterClassModel: CustomStringConvertible { } extension _CharacterClassModel { - public func makeAST() -> AST.Node? { + public func makeDSLTreeCharacterClass() -> DSLTree.CustomCharacterClass? { + // FIXME: Implement in DSLTree instead of wrapping an AST atom + switch makeAST() { + case .atom(let atom): + return .init(members: [.atom(.unconverted(.init(ast: atom)))]) + default: + return nil + } + } + + internal func makeAST() -> AST.Node? { let inv = isInverted func esc(_ b: AST.Atom.EscapedBuiltin) -> AST.Node { @@ -375,7 +389,7 @@ extension DSLTree.Atom { var characterClass: _CharacterClassModel? { switch self { case let .unconverted(a): - return a.characterClass + return a.ast.characterClass default: return nil } diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index 0a7d6fc59..bf4489a68 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -136,7 +136,7 @@ func customTest( class CustomRegexComponentTests: XCTestCase { // TODO: Refactor below into more exhaustive, declarative // tests. - func testCustomRegexComponents() { + func testCustomRegexComponents() throws { customTest( Regex { Numbler() @@ -178,14 +178,13 @@ class CustomRegexComponentTests: XCTestCase { } } - guard let res3 = "ab123c".firstMatch(of: regex3) else { - XCTFail() - return - } + let str = "ab123c" + let res3 = try XCTUnwrap(str.firstMatch(of: regex3)) - XCTAssertEqual(res3.range, "ab123c".index(atOffset: 2)..<"ab123c".index(atOffset: 5)) - XCTAssertEqual(res3.output.0, "123") - XCTAssertEqual(res3.output.1, "123") + let expectedSubstring = str.dropFirst(2).prefix(3) + XCTAssertEqual(res3.range, expectedSubstring.startIndex.. Date: Tue, 19 Apr 2022 13:50:10 -0700 Subject: [PATCH 081/133] Expose `matches`, `ranges` and `split` (#304) * Expose `matches`, `ranges` and `split` Publicize these API per the String Processing Algorithms proposal. The proposed ones return generic `Collection`, empowered by SE-0346. For now we'll wrap the results with a concrete `Array` until the language feature is ready. Co-authored-by: Michael Ilseman --- .../Algorithms/Algorithms/Ranges.swift | 29 +++++++++++++-- .../Algorithms/Algorithms/Split.swift | 35 +++++++++++++------ .../Algorithms/Matching/MatchReplace.swift | 2 +- .../Algorithms/Matching/Matches.swift | 15 ++++---- Tests/RegexBuilderTests/AlgorithmsTests.swift | 12 +++---- Tests/RegexTests/AlgorithmsTests.swift | 6 ++-- 6 files changed, 69 insertions(+), 30 deletions(-) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift index f1861fcf2..853c73271 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift @@ -175,12 +175,24 @@ extension BidirectionalCollection { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { - // FIXME: Replace `RangesCollection` when SE-0346 is enabled func ranges( of other: S ) -> RangesCollection> where S.Element == Element { ranges(of: ZSearcher(pattern: Array(other), by: ==)) } + + // FIXME: Return `some Collection>` for SE-0346 + /// Finds and returns the ranges of the all occurrences of a given sequence + /// within the collection. + /// - Parameter other: The sequence to search for. + /// - Returns: A collection of ranges of all occurrences of `other`. Returns + /// an empty collection if `other` is not found. + @available(SwiftStdlib 5.7, *) + public func ranges( + of other: S + ) -> [Range] where S.Element == Element { + ranges(of: ZSearcher(pattern: Array(other), by: ==)).map { $0 } + } } extension BidirectionalCollection where Element: Equatable { @@ -217,8 +229,8 @@ extension BidirectionalCollection where Element: Comparable { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - // FIXME: Replace `RangesCollection` when SE-0346 is enabled @available(SwiftStdlib 5.7, *) + @_disfavoredOverload func ranges( of regex: R ) -> RangesCollection> { @@ -231,4 +243,17 @@ extension BidirectionalCollection where SubSequence == Substring { ) -> ReversedRangesCollection> { rangesFromBack(of: RegexConsumer(regex)) } + + // FIXME: Return `some Collection>` for SE-0346 + /// Finds and returns the ranges of the all occurrences of a given sequence + /// within the collection. + /// - Parameter regex: The regex to search for. + /// - Returns: A collection or ranges in the receiver of all occurrences of + /// `regex`. Returns an empty collection if `regex` is not found. + @available(SwiftStdlib 5.7, *) + public func ranges( + of regex: R + ) -> [Range] { + Array(ranges(of: RegexConsumer(regex))) + } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift index 485bc3b7f..8c7a9832d 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -233,16 +233,24 @@ extension BidirectionalCollection where Element: Equatable { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { - // FIXME: Replace `SplitCollection` when SE-0346 is enabled + @_disfavoredOverload + func split( + by separator: S + ) -> SplitCollection> where S.Element == Element { + split(by: ZSearcher(pattern: Array(separator), by: ==)) + } + + // FIXME: Return `some Collection` for SE-0346 /// Returns the longest possible subsequences of the collection, in order, /// around elements equal to the given separator. /// - Parameter separator: The element to be split upon. /// - Returns: A collection of subsequences, split from this collection's /// elements. - func split( + @available(SwiftStdlib 5.7, *) + public func split( by separator: S - ) -> SplitCollection> where S.Element == Element { - split(by: ZSearcher(pattern: Array(separator), by: ==)) + ) -> [SubSequence] where S.Element == Element { + Array(split(by: ZSearcher(pattern: Array(separator), by: ==))) } } @@ -282,12 +290,7 @@ extension BidirectionalCollection where Element: Comparable { @available(SwiftStdlib 5.7, *) extension BidirectionalCollection where SubSequence == Substring { - // FIXME: Replace `SplitCollection` when SE-0346 is enabled - /// Returns the longest possible subsequences of the collection, in order, - /// around elements equal to the given separator. - /// - Parameter separator: A regex describing elements to be split upon. - /// - Returns: A collection of substrings, split from this collection's - /// elements. + @_disfavoredOverload func split( by separator: R ) -> SplitCollection> { @@ -299,4 +302,16 @@ extension BidirectionalCollection where SubSequence == Substring { ) -> ReversedSplitCollection> { splitFromBack(by: RegexConsumer(separator)) } + + // FIXME: Return `some Collection` for SE-0346 + /// Returns the longest possible subsequences of the collection, in order, + /// around elements equal to the given separator. + /// - Parameter separator: A regex describing elements to be split upon. + /// - Returns: A collection of substrings, split from this collection's + /// elements. + public func split( + by separator: R + ) -> [SubSequence] { + Array(split(by: RegexConsumer(separator))) + } } diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift index 8485182de..09e021a29 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift @@ -139,7 +139,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { var result = Self() result.append(contentsOf: self[..( of regex: R ) -> MatchesCollection> { @@ -202,10 +199,14 @@ extension BidirectionalCollection where SubSequence == Substring { matchesFromBack(of: RegexConsumer(regex)) } - // FIXME: Replace the returned value as `some Collection.Match> - // when SE-0346 is enabled + // FIXME: Return `some Collection.Match> for SE-0346 + /// Returns a collection containing all matches of the specified regex. + /// - Parameter regex: The regex to search for. + /// - Returns: A collection of matches of `regex`. @available(SwiftStdlib 5.7, *) - func _matches(of r: R) -> [Regex.Match] { + public func matches( + of r: R + ) -> [Regex.Match] { let slice = self[...] var start = self.startIndex let end = self.endIndex diff --git a/Tests/RegexBuilderTests/AlgorithmsTests.swift b/Tests/RegexBuilderTests/AlgorithmsTests.swift index cf117690a..793054cd1 100644 --- a/Tests/RegexBuilderTests/AlgorithmsTests.swift +++ b/Tests/RegexBuilderTests/AlgorithmsTests.swift @@ -15,13 +15,11 @@ import _StringProcessing @available(SwiftStdlib 5.7, *) class RegexConsumerTests: XCTestCase { - // FIXME: enable this test when we update the return type of `matches(of:)` - // when SE-0346 is available - // func testMatches() { - // let regex = Capture(OneOrMore(.digit)) { 2 * Int($0)! } - // let str = "foo 160 bar 99 baz" - // XCTAssertEqual(str.matches(of: regex).map(\.result.1), [320, 198]) - // } + func testMatches() { + let regex = Capture(OneOrMore(.digit)) { 2 * Int($0)! } + let str = "foo 160 bar 99 baz" + XCTAssertEqual(str.matches(of: regex).map(\.output.1), [320, 198]) + } func testMatchReplace() { func replaceTest( diff --git a/Tests/RegexTests/AlgorithmsTests.swift b/Tests/RegexTests/AlgorithmsTests.swift index 8e77a8977..a7832a0f9 100644 --- a/Tests/RegexTests/AlgorithmsTests.swift +++ b/Tests/RegexTests/AlgorithmsTests.swift @@ -163,13 +163,13 @@ class RegexConsumerTests: XCTestCase { XCTAssertEqual(s2.replacing(regex, with: ""), "") XCTAssertEqual( - s._matches(of: regex).map(\.0), + s.matches(of: regex).map(\.0), ["aaa", "aaaaaa", "aaaaaaaaaa"]) XCTAssertEqual( - s1._matches(of: regex).map(\.0), + s1.matches(of: regex).map(\.0), ["aaaaaa", "aaaaaaaaaa"]) XCTAssertEqual( - s2._matches(of: regex).map(\.0), + s2.matches(of: regex).map(\.0), ["aa"]) } } From 15355bfd33d82b4eb5f379ed0cd903f5a5e61fcb Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Tue, 19 Apr 2022 15:51:23 -0600 Subject: [PATCH 082/133] Convenience quoting (#305) --- Sources/_StringProcessing/Regex/Match.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 4b2f117e4..45b177867 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -187,3 +187,10 @@ extension Substring { try? r.regex.prefixMatch(in: self) } } + +@available(SwiftStdlib 5.7, *) +extension Regex { + public init(quoting string: String) { + self.init(node: .quotedLiteral(string)) + } +} From 46b9a0fcee56cbb3040ce29be727db322be76bf2 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Wed, 20 Apr 2022 16:38:21 -0600 Subject: [PATCH 083/133] Remove compiling argument label (#306) --- Documentation/Evolution/RegexLiterals.md | 4 ++-- .../Evolution/RegexSyntaxRunTimeConstruction.md | 4 ++-- Documentation/Evolution/RegexTypeOverview.md | 6 +++--- Sources/Exercises/Participants/RegexParticipant.swift | 2 +- Sources/_StringProcessing/Regex/AnyRegexOutput.swift | 4 ++-- Sources/_StringProcessing/Regex/Core.swift | 2 +- Tests/RegexBuilderTests/MotivationTests.swift | 4 ++-- Tests/RegexBuilderTests/RegexDSLTests.swift | 6 +++--- Tests/RegexTests/AlgorithmsTests.swift | 10 +++++----- Tests/RegexTests/MatchTests.swift | 10 +++++----- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Documentation/Evolution/RegexLiterals.md b/Documentation/Evolution/RegexLiterals.md index 3c12c9c7a..3643590d4 100644 --- a/Documentation/Evolution/RegexLiterals.md +++ b/Documentation/Evolution/RegexLiterals.md @@ -12,7 +12,7 @@ In *[Regex Type and Overview][regex-type]* we introduced the `Regex` type, which ```swift let pattern = #"(\w+)\s\s+(\S+)\s\s+((?:(?!\s\s).)*)\s\s+(.*)"# -let regex = try! Regex(compiling: pattern) +let regex = try! Regex(pattern) // regex: Regex ``` @@ -366,7 +366,7 @@ However we decided against this because: ### No custom literal -Instead of adding a custom regex literal, we could require users to explicitly write `try! Regex(compiling: "[abc]+")`. This would be similar to `NSRegularExpression`, and loses all the benefits of parsing the literal at compile time. This would mean: +Instead of adding a custom regex literal, we could require users to explicitly write `try! Regex("[abc]+")`. This would be similar to `NSRegularExpression`, and loses all the benefits of parsing the literal at compile time. This would mean: - No source tooling support (e.g syntax highlighting, refactoring actions) would be available. - Parse errors would be diagnosed at run time rather than at compile time. diff --git a/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md index 3fb0841e3..1a868aa04 100644 --- a/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md +++ b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md @@ -50,11 +50,11 @@ We propose run-time construction of `Regex` from a best-in-class treatment of fa ```swift let pattern = #"(\w+)\s\s+(\S+)\s\s+((?:(?!\s\s).)*)\s\s+(.*)"# -let regex = try! Regex(compiling: pattern) +let regex = try! Regex(pattern) // regex: Regex let regex: Regex<(Substring, Substring, Substring, Substring, Substring)> = - try! Regex(compiling: pattern) + try! Regex(pattern) ``` ### Syntax diff --git a/Documentation/Evolution/RegexTypeOverview.md b/Documentation/Evolution/RegexTypeOverview.md index bce336551..9fd369dbf 100644 --- a/Documentation/Evolution/RegexTypeOverview.md +++ b/Documentation/Evolution/RegexTypeOverview.md @@ -134,11 +134,11 @@ Regexes can be created at run time from a string containing familiar regex synta ```swift let pattern = #"(\w+)\s\s+(\S+)\s\s+((?:(?!\s\s).)*)\s\s+(.*)"# -let regex = try! Regex(compiling: pattern) +let regex = try! Regex(pattern) // regex: Regex let regex: Regex<(Substring, Substring, Substring, Substring, Substring)> = - try! Regex(compiling: pattern) + try! Regex(pattern) ``` *Note*: The syntax accepted and further details on run-time compilation, including `AnyRegexOutput` and extended syntaxes, are discussed in [Run-time Regex Construction][pitches]. @@ -300,7 +300,7 @@ Regex targets [UTS\#18 Level 2](https://www.unicode.org/reports/tr18/#Extended_U ```swift /// A regex represents a string processing algorithm. /// -/// let regex = try Regex(compiling: "a(.*)b") +/// let regex = try Regex("a(.*)b") /// let match = "cbaxb".firstMatch(of: regex) /// print(match.0) // "axb" /// print(match.1) // "x" diff --git a/Sources/Exercises/Participants/RegexParticipant.swift b/Sources/Exercises/Participants/RegexParticipant.swift index 6c53b3adf..627f9583b 100644 --- a/Sources/Exercises/Participants/RegexParticipant.swift +++ b/Sources/Exercises/Participants/RegexParticipant.swift @@ -70,7 +70,7 @@ private func graphemeBreakPropertyDataLiteral( forLine line: String ) -> GraphemeBreakEntry? { let regex = try! Regex( - compiling: #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, + #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, as: (Substring, Substring, Substring?, Substring).self) return graphemeBreakPropertyData(forLine: line, using: regex) } diff --git a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift index 8dacb5d50..0d018aa81 100644 --- a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift +++ b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift @@ -14,7 +14,7 @@ @available(SwiftStdlib 5.7, *) extension Regex where Output == AnyRegexOutput { /// Parse and compile `pattern`, resulting in an existentially-typed capture list. - public init(compiling pattern: String) throws { + public init(_ pattern: String) throws { self.init(ast: try parse(pattern, .traditional)) } } @@ -23,7 +23,7 @@ extension Regex where Output == AnyRegexOutput { extension Regex { /// Parse and compile `pattern`, resulting in a strongly-typed capture list. public init( - compiling pattern: String, + _ pattern: String, as: Output.Type = Output.self ) throws { self.init(ast: try parse(pattern, .traditional)) diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index 56a14da51..d77784df4 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -21,7 +21,7 @@ public protocol RegexComponent { /// A regex represents a string processing algorithm. /// -/// let regex = try Regex(compiling: "a(.*)b") +/// let regex = try Regex("a(.*)b") /// let match = "cbaxb".firstMatch(of: regex) /// print(match.0) // "axb" /// print(match.1) // "x" diff --git a/Tests/RegexBuilderTests/MotivationTests.swift b/Tests/RegexBuilderTests/MotivationTests.swift index 1927b9ae4..22e790e2d 100644 --- a/Tests/RegexBuilderTests/MotivationTests.swift +++ b/Tests/RegexBuilderTests/MotivationTests.swift @@ -139,7 +139,7 @@ private func processWithRuntimeDynamicRegex( _ line: String ) -> Transaction? { // FIXME: Shouldn't this init throw? - let regex = try! Regex(compiling: pattern) + let regex = try! Regex(pattern) // guard let result = line.match(regex) else { return nil } // @@ -156,7 +156,7 @@ private func processWithRuntimeDynamicRegex( @available(macOS 12.0, *) private func processWithRuntimeStaticRegex(_ line: String) -> Transaction? { let regex: Regex<(Substring, Substring, Substring, Substring, Substring)> - = try! Regex(compiling: pattern) + = try! Regex(pattern) return process(line, using: regex) } diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 58f847f32..6d74de826 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -666,7 +666,7 @@ class RegexDSLTests: XCTestCase { do { let regexLiteral = try Regex( - compiling: #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, + #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, as: (Substring, Substring, Substring?, Substring).self) let maybeMatchResult = line.wholeMatch(of: regexLiteral) let matchResult = try XCTUnwrap(maybeMatchResult) @@ -680,7 +680,7 @@ class RegexDSLTests: XCTestCase { func testDynamicCaptures() throws { do { - let regex = try Regex(compiling: "aabcc.") + let regex = try Regex("aabcc.") let line = "aabccd" let match = try XCTUnwrap(line.wholeMatch(of: regex)) XCTAssertEqual(match.0, line[...]) @@ -689,7 +689,7 @@ class RegexDSLTests: XCTestCase { } do { let regex = try Regex( - compiling: #""" + #""" (?[0-9A-F]+)(?:\.\.(?[0-9A-F]+))?\s+;\s+(?\w+).* """#) let line = """ diff --git a/Tests/RegexTests/AlgorithmsTests.swift b/Tests/RegexTests/AlgorithmsTests.swift index a7832a0f9..a788ad13c 100644 --- a/Tests/RegexTests/AlgorithmsTests.swift +++ b/Tests/RegexTests/AlgorithmsTests.swift @@ -32,7 +32,7 @@ class RegexConsumerTests: XCTestCase { _ expected: [Range], file: StaticString = #file, line: UInt = #line ) { - let regex = try! Regex(compiling: regex) + let regex = try! Regex(regex) let actualSeq: [Range] = string[...].ranges(of: regex).map(string.offsets(of:)) XCTAssertEqual(actualSeq, expected, file: file, line: line) @@ -69,7 +69,7 @@ class RegexConsumerTests: XCTestCase { _ expected: [Substring], file: StaticString = #file, line: UInt = #line ) { - let regex = try! Regex(compiling: regex) + let regex = try! Regex(regex) let actual = Array(string.split(by: regex)) XCTAssertEqual(actual, expected, file: file, line: line) } @@ -89,7 +89,7 @@ class RegexConsumerTests: XCTestCase { _ expected: String, file: StaticString = #file, line: UInt = #line ) { - let regex = try! Regex(compiling: regex) + let regex = try! Regex(regex) let actual = string.replacing(regex, with: replacement) XCTAssertEqual(actual, expected, file: file, line: line) } @@ -108,7 +108,7 @@ class RegexConsumerTests: XCTestCase { } func testAdHoc() { - let r = try! Regex(compiling: "a|b+") + let r = try! Regex("a|b+") XCTAssert("palindrome".contains(r)) XCTAssert("botany".contains(r)) @@ -142,7 +142,7 @@ class RegexConsumerTests: XCTestCase { let s = "aaa | aaaaaa | aaaaaaaaaa" let s1 = s.dropFirst(6) // "aaaaaa | aaaaaaaaaa" let s2 = s1.dropLast(17) // "aa" - let regex = try! Regex(compiling: "a+") + let regex = try! Regex("a+") XCTAssertEqual(s.firstMatch(of: regex)?.0, "aaa") XCTAssertEqual(s1.firstMatch(of: regex)?.0, "aaaaaa") diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index 4d9ed4d01..e00c77f56 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -1290,11 +1290,11 @@ extension RegexTests { 04: Arkansas 05: California """ - XCTAssertTrue(string.contains(try Regex(compiling: #"^\d+"#))) - XCTAssertEqual(string.ranges(of: try Regex(compiling: #"^\d+"#)).count, 1) - XCTAssertEqual(string.ranges(of: try Regex(compiling: #"(?m)^\d+"#)).count, 5) + XCTAssertTrue(string.contains(try Regex(#"^\d+"#))) + XCTAssertEqual(string.ranges(of: try Regex(#"^\d+"#)).count, 1) + XCTAssertEqual(string.ranges(of: try Regex(#"(?m)^\d+"#)).count, 5) - let regex = try Regex(compiling: #"^\d+: [\w ]+$"#) + let regex = try Regex(#"^\d+: [\w ]+$"#) XCTAssertFalse(string.contains(regex)) let allRanges = string.ranges(of: regex.anchorsMatchLineEndings()) XCTAssertEqual(allRanges.count, 5) @@ -1333,7 +1333,7 @@ extension RegexTests { } func testOptionMethods() throws { - let regex = try Regex(compiling: "c.f.") + let regex = try Regex("c.f.") XCTAssertTrue ("cafe".contains(regex)) XCTAssertFalse("CaFe".contains(regex)) From b24d3ea48808d9362406176eeeaaff10f8599508 Mon Sep 17 00:00:00 2001 From: Tina Liu <49205802+itingliu@users.noreply.github.com> Date: Thu, 21 Apr 2022 10:53:11 -0700 Subject: [PATCH 084/133] Move the closure argument to the end of the arg list (#307) Move the closure argument in `replace` and `replacing` to the end of the argument list for trailing closure syntax. Add a test for replacing within a range. --- .../Evolution/StringProcessingAlgorithms.md | 24 +++++----- .../Algorithms/Matching/MatchReplace.swift | 32 +++++++------- Tests/RegexBuilderTests/AlgorithmsTests.swift | 44 +++++++++++++++++++ 3 files changed, 72 insertions(+), 28 deletions(-) diff --git a/Documentation/Evolution/StringProcessingAlgorithms.md b/Documentation/Evolution/StringProcessingAlgorithms.md index b976c562e..8680ff75a 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -511,48 +511,48 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// the given regex are replaced by another regex match. /// - Parameters: /// - regex: A regex describing the sequence to replace. - /// - replacement: A closure that receives the full match information, - /// including captures, and returns a replacement collection. /// - subrange: The range in the collection in which to search for `regex`. /// - maxReplacements: A number specifying how many occurrences of the /// sequence matching `regex` to replace. Default is `Int.max`. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. public func replacing( _ regex: R, - with replacement: (RegexMatch) throws -> Replacement, subrange: Range, - maxReplacements: Int = .max + maxReplacements: Int = .max, + with replacement: (RegexMatch) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element /// Returns a new collection in which all occurrences of a sequence matching /// the given regex are replaced by another collection. /// - Parameters: /// - regex: A regex describing the sequence to replace. - /// - replacement: A closure that receives the full match information, - /// including captures, and returns a replacement collection. /// - maxReplacements: A number specifying how many occurrences of the /// sequence matching `regex` to replace. Default is `Int.max`. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. public func replacing( _ regex: R, - with replacement: (RegexMatch) throws -> Replacement, - maxReplacements: Int = .max + maxReplacements: Int = .max, + with replacement: (RegexMatch) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element /// Replaces all occurrences of the sequence matching the given regex with /// a given collection. /// - Parameters: /// - regex: A regex describing the sequence to replace. - /// - replacement: A closure that receives the full match information, - /// including captures, and returns a replacement collection. /// - maxReplacements: A number specifying how many occurrences of the /// sequence matching `regex` to replace. Default is `Int.max`. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. public mutating func replace( _ regex: R, - with replacement: (RegexMatch) throws -> Replacement, - maxReplacements: Int = .max + maxReplacements: Int = .max, + with replacement: (RegexMatch) throws -> Replacement ) rethrows where Replacement.Element == Element } ``` diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift index 09e021a29..206d68554 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift @@ -118,19 +118,19 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// the given regex are replaced by another regex match. /// - Parameters: /// - regex: A regex describing the sequence to replace. - /// - replacement: A closure that receives the full match information, - /// including captures, and returns a replacement collection. /// - subrange: The range in the collection in which to search for `regex`. /// - maxReplacements: A number specifying how many occurrences of the /// sequence matching `regex` to replace. Default is `Int.max`. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, - with replacement: (Regex.Match) throws -> Replacement, subrange: Range, - maxReplacements: Int = .max + maxReplacements: Int = .max, + with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element { precondition(maxReplacements >= 0) @@ -155,43 +155,43 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// the given regex are replaced by another collection. /// - Parameters: /// - regex: A regex describing the sequence to replace. - /// - replacement: A closure that receives the full match information, - /// including captures, and returns a replacement collection. /// - maxReplacements: A number specifying how many occurrences of the /// sequence matching `regex` to replace. Default is `Int.max`. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, - with replacement: (Regex.Match) throws -> Replacement, - maxReplacements: Int = .max + maxReplacements: Int = .max, + with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element { try replacing( regex, - with: replacement, subrange: startIndex..( _ regex: R, - with replacement: (Regex.Match) throws -> Replacement, - maxReplacements: Int = .max + maxReplacements: Int = .max, + with replacement: (Regex.Match) throws -> Replacement ) rethrows where Replacement.Element == Element { self = try replacing( regex, - with: replacement, subrange: startIndex..( + _ regex: R, + input: String, + _ replace: (Regex.Match) -> String, + _ tests: (subrange: Range, maxReplacement: Int, result: String)..., + file: StaticString = #file, + line: UInt = #line + ) { + for (subrange, maxReplacement, result) in tests { + XCTAssertEqual(input.replacing(regex, subrange: subrange, maxReplacements: maxReplacement, with: replace), result, file: file, line: line) + } + } + + let int = Capture(OneOrMore(.digit)) { Int($0)! } + + let addition = "9+16, 0+3, 5+5, 99+1" + + replaceTest( + Regex { int; "+"; int }, + input: "9+16, 0+3, 5+5, 99+1", + { match in "\(match.output.1 + match.output.2)" }, + + (subrange: addition.startIndex.. Date: Thu, 21 Apr 2022 14:26:50 -0500 Subject: [PATCH 085/133] Adds RegexBuilder.CharacterClass.anyUnicodeScalar (#315) This provides a RegexBuilder API that represents the same as `\O` in regex syntax. --- Sources/RegexBuilder/CharacterClass.swift | 4 ++++ .../_StringProcessing/_CharacterClassModel.swift | 15 ++++++++++++++- Tests/RegexTests/MatchTests.swift | 12 +++++------- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Sources/RegexBuilder/CharacterClass.swift b/Sources/RegexBuilder/CharacterClass.swift index 0087d734a..b7d8454bb 100644 --- a/Sources/RegexBuilder/CharacterClass.swift +++ b/Sources/RegexBuilder/CharacterClass.swift @@ -51,6 +51,10 @@ extension RegexComponent where Self == CharacterClass { public static var anyGrapheme: CharacterClass { .init(unconverted: .anyGrapheme) } + + public static var anyUnicodeScalar: CharacterClass { + .init(unconverted: .anyUnicodeScalar) + } public static var whitespace: CharacterClass { .init(unconverted: .whitespace) diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index 2debcda9d..c02725e33 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -33,6 +33,8 @@ public struct _CharacterClassModel: Hashable { case any /// Any grapheme cluster case anyGrapheme + /// Any Unicode scalar + case anyScalar /// Character.isDigit case digit /// Character.isHexDigit @@ -159,8 +161,12 @@ public struct _CharacterClassModel: Hashable { case .graphemeCluster: let c = str[i] var matched: Bool + var next = str.index(after: i) switch cc { case .any, .anyGrapheme: matched = true + case .anyScalar: + matched = true + next = str.unicodeScalars.index(after: i) case .digit: matched = c.isNumber && (c.isASCII || !options.usesASCIIDigits) case .hexDigit: @@ -178,12 +184,13 @@ public struct _CharacterClassModel: Hashable { if isInverted { matched.toggle() } - return matched ? str.index(after: i) : nil + return matched ? next : nil case .unicodeScalar: let c = str.unicodeScalars[i] var matched: Bool switch cc { case .any: matched = true + case .anyScalar: matched = true case .anyGrapheme: fatalError("Not matched in this mode") case .digit: matched = c.properties.numericType != nil && (c.isASCII || !options.usesASCIIDigits) @@ -228,6 +235,10 @@ extension _CharacterClassModel { .init(cc: .anyGrapheme, matchLevel: .graphemeCluster) } + public static var anyUnicodeScalar: _CharacterClassModel { + .init(cc: .any, matchLevel: .unicodeScalar) + } + public static var whitespace: _CharacterClassModel { .init(cc: .whitespace, matchLevel: .graphemeCluster) } @@ -279,6 +290,7 @@ extension _CharacterClassModel.Representation: CustomStringConvertible { switch self { case .any: return "" case .anyGrapheme: return "" + case .anyScalar: return "" case .digit: return "" case .hexDigit: return "" case .horizontalWhitespace: return "" @@ -445,6 +457,7 @@ extension AST.Atom.EscapedBuiltin { case .notWordCharacter: return .word.inverted case .graphemeCluster: return .anyGrapheme + case .trueAnychar: return .anyUnicodeScalar default: return nil diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index e00c77f56..dab53cc1c 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -1512,13 +1512,11 @@ extension RegexTests { (eDecomposed, false)) // FIXME: \O is unsupported - firstMatchTest(#"\O\u{301}"#, input: eDecomposed, match: eDecomposed, - xfail: true) - firstMatchTest(#"e\O"#, input: eDecomposed, match: eDecomposed, - xfail: true) - firstMatchTest(#"\O\u{301}"#, input: eComposed, match: nil, - xfail: true) - firstMatchTest(#"e\O"#, input: eComposed, match: nil, + firstMatchTest(#"(?u)\O\u{301}"#, input: eDecomposed, match: eDecomposed) + firstMatchTest(#"(?u)e\O"#, input: eDecomposed, match: eDecomposed, + xfail: true) + firstMatchTest(#"\O"#, input: eComposed, match: eComposed) + firstMatchTest(#"\O"#, input: eDecomposed, match: nil, xfail: true) matchTest( From 4857bc719518571042a57f9a95d3caba0fe2ca05 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 21 Apr 2022 14:36:28 -0500 Subject: [PATCH 086/133] Allow setting any of the three quant behaviors (#311) This also moves QuantificationBehavior from the RegexBuilder module down to _StringProcessing, and renames it to RegexRepetitionBehavior. --- Sources/RegexBuilder/DSL.swift | 44 +-- Sources/RegexBuilder/Variadics.swift | 308 +++++++++--------- .../VariadicsGenerator.swift | 10 +- .../Regex/AST/MatchingOptions.swift | 4 + Sources/_StringProcessing/ByteCodeGen.swift | 4 +- .../_StringProcessing/MatchingOptions.swift | 34 +- Sources/_StringProcessing/Regex/Options.swift | 66 +++- Tests/RegexBuilderTests/RegexDSLTests.swift | 101 ++++-- 8 files changed, 332 insertions(+), 239 deletions(-) diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 97bc35154..62aacc4af 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -94,40 +94,20 @@ extension UnicodeScalar: RegexComponent { // Note: Quantifiers are currently gyb'd. -/// Specifies how much to attempt to match when using a quantifier. -@available(SwiftStdlib 5.7, *) -public struct QuantificationBehavior { - internal enum Kind { - case eagerly - case reluctantly - case possessively - } - - var kind: Kind - - internal var astKind: DSLTree._AST.QuantificationKind { - switch kind { - case .eagerly: return .eager - case .reluctantly: return .reluctant - case .possessively: return .possessive - } - } -} - extension DSLTree.Node { /// Generates a DSLTree node for a repeated range of the given DSLTree node. /// Individual public API functions are in the generated Variadics.swift file. @available(SwiftStdlib 5.7, *) static func repeating( _ range: Range, - _ behavior: QuantificationBehavior?, + _ behavior: RegexRepetitionBehavior?, _ node: DSLTree.Node ) -> DSLTree.Node { // TODO: Throw these as errors assert(range.lowerBound >= 0, "Cannot specify a negative lower bound") assert(!range.isEmpty, "Cannot specify an empty range") - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default switch (range.lowerBound, range.upperBound) { case (0, Int.max): // 0... @@ -147,26 +127,6 @@ extension DSLTree.Node { } } -@available(SwiftStdlib 5.7, *) -extension QuantificationBehavior { - /// Match as much of the input string as possible, backtracking when - /// necessary. - public static var eagerly: QuantificationBehavior { - .init(kind: .eagerly) - } - - /// Match as little of the input string as possible, expanding the matched - /// region as necessary to complete a match. - public static var reluctantly: QuantificationBehavior { - .init(kind: .reluctantly) - } - - /// Match as much of the input string as possible, performing no backtracking. - public static var possessively: QuantificationBehavior { - .init(kind: .possessively) - } -} - @available(SwiftStdlib 5.7, *) public struct OneOrMore: _BuiltinRegexComponent { public var regex: Regex diff --git a/Sources/RegexBuilder/Variadics.swift b/Sources/RegexBuilder/Variadics.swift index 3697be15e..356853ec5 100644 --- a/Sources/RegexBuilder/Variadics.swift +++ b/Sources/RegexBuilder/Variadics.swift @@ -615,9 +615,9 @@ extension Optionally { @_disfavoredOverload public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == Substring { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -627,10 +627,10 @@ extension Optionally { @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == Substring { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -650,9 +650,9 @@ extension ZeroOrMore { @_disfavoredOverload public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == Substring { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -662,10 +662,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == Substring { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -677,9 +677,9 @@ extension OneOrMore { @_disfavoredOverload public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == Substring { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -689,10 +689,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == Substring { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -727,7 +727,7 @@ extension Repeat { public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == Substring, R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == Substring, R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -758,10 +758,10 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -780,9 +780,9 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -791,10 +791,10 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -805,9 +805,9 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -816,10 +816,10 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -851,7 +851,7 @@ extension Repeat { public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -881,10 +881,10 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -903,9 +903,9 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -914,10 +914,10 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -928,9 +928,9 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -939,10 +939,10 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -974,7 +974,7 @@ extension Repeat { public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1004,10 +1004,10 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1026,9 +1026,9 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1037,10 +1037,10 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1051,9 +1051,9 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1062,10 +1062,10 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1097,7 +1097,7 @@ extension Repeat { public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1127,10 +1127,10 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1149,9 +1149,9 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1160,10 +1160,10 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1174,9 +1174,9 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1185,10 +1185,10 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1220,7 +1220,7 @@ extension Repeat { public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1250,10 +1250,10 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1272,9 +1272,9 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1283,10 +1283,10 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1297,9 +1297,9 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1308,10 +1308,10 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1343,7 +1343,7 @@ extension Repeat { public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1373,10 +1373,10 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1395,9 +1395,9 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1406,10 +1406,10 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1420,9 +1420,9 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1431,10 +1431,10 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1466,7 +1466,7 @@ extension Repeat { public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1496,10 +1496,10 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1518,9 +1518,9 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1529,10 +1529,10 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1543,9 +1543,9 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1554,10 +1554,10 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1589,7 +1589,7 @@ extension Repeat { public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1619,10 +1619,10 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1641,9 +1641,9 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1652,10 +1652,10 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1666,9 +1666,9 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1677,10 +1677,10 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1712,7 +1712,7 @@ extension Repeat { public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1742,10 +1742,10 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1764,9 +1764,9 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1775,10 +1775,10 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1789,9 +1789,9 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1800,10 +1800,10 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1835,7 +1835,7 @@ extension Repeat { public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } @@ -1865,10 +1865,10 @@ extension Optionally { extension Optionally { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1887,9 +1887,9 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } @@ -1898,10 +1898,10 @@ extension ZeroOrMore { extension ZeroOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1912,9 +1912,9 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } @@ -1923,10 +1923,10 @@ extension OneOrMore { extension OneOrMore { @available(SwiftStdlib 5.7, *) public init( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1958,7 +1958,7 @@ extension Repeat { public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) \(params.whereClauseForInit) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.\(kind.astQuantifierAmount), kind, component.regex.root)) } } @@ -389,10 +389,10 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) \(params.disfavored)\ public init<\(params.genericParams)>( - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @\(concatBuilderName) _ component: () -> Component ) \(params.whereClauseForInit) { - let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.\(kind.astQuantifierAmount), kind, component().regex.root)) } } @@ -508,7 +508,7 @@ struct VariadicsGenerator: ParsableCommand { public init<\(params.genericParams), R: RangeExpression>( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior? = nil + _ behavior: RegexRepetitionBehavior? = nil ) \(params.repeatingWhereClause) { self.init(node: .repeating(expression.relative(to: 0.. Regex { - wrapInOption(.reluctantByDefault, addingIf: useReluctantQuantifiers) + /// Passing `.eager` or `.reluctant` to this method corresponds to applying + /// the `(?-U)` or `(?U)` option in regex syntax, respectively. + /// + /// - Parameter behavior: The default behavior to use for quantifiers. + public func repetitionBehavior(_ behavior: RegexRepetitionBehavior) -> Regex { + if behavior == .possessive { + return wrapInOption(.possessiveByDefault, addingIf: true) + } else { + return wrapInOption(.reluctantByDefault, addingIf: behavior == .reluctant) + } } /// Returns a regular expression that matches with the specified semantic @@ -183,6 +189,46 @@ public struct RegexWordBoundaryKind: Hashable { } } +/// Specifies how much to attempt to match when using a quantifier. +@available(SwiftStdlib 5.7, *) +public struct RegexRepetitionBehavior: Hashable { + internal enum Kind { + case eager + case reluctant + case possessive + } + + var kind: Kind + + @_spi(RegexBuilder) public var dslTreeKind: DSLTree._AST.QuantificationKind { + switch kind { + case .eager: return .eager + case .reluctant: return .reluctant + case .possessive: return .possessive + } + } +} + +@available(SwiftStdlib 5.7, *) +extension RegexRepetitionBehavior { + /// Match as much of the input string as possible, backtracking when + /// necessary. + public static var eager: Self { + .init(kind: .eager) + } + + /// Match as little of the input string as possible, expanding the matched + /// region as necessary to complete a match. + public static var reluctant: Self { + .init(kind: .reluctant) + } + + /// Match as much of the input string as possible, performing no backtracking. + public static var possessive: Self { + .init(kind: .possessive) + } +} + // MARK: - Helper method @available(SwiftStdlib 5.7, *) diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 6d74de826..cc5afda39 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -272,7 +272,7 @@ class RegexDSLTests: XCTestCase { OneOrMore(.word) Anchor.wordBoundary } - OneOrMore(.any, .reluctantly) + OneOrMore(.any, .reluctant) "stop" " " @@ -281,7 +281,7 @@ class RegexDSLTests: XCTestCase { Anchor.wordBoundary } .wordBoundaryKind(.unicodeLevel1) - OneOrMore(.any, .reluctantly) + OneOrMore(.any, .reluctant) "stop" } } @@ -293,14 +293,14 @@ class RegexDSLTests: XCTestCase { Capture { // Reluctant behavior due to option OneOrMore(.anyOf("abcd")) - .reluctantQuantifiers() + .repetitionBehavior(.reluctant) } ZeroOrMore("a"..."z") Capture { // Eager behavior due to explicit parameter, despite option - OneOrMore(.digit, .eagerly) - .reluctantQuantifiers() + OneOrMore(.digit, .eager) + .repetitionBehavior(.reluctant) } ZeroOrMore(.digit) } @@ -319,6 +319,7 @@ class RegexDSLTests: XCTestCase { } func testQuantificationBehavior() throws { + // Eager by default try _testDSLCaptures( ("abc1def2", ("abc1def2", "2")), matchType: (Substring, Substring).self, ==) @@ -328,41 +329,93 @@ class RegexDSLTests: XCTestCase { ZeroOrMore(.any) } + // Explicitly reluctant try _testDSLCaptures( ("abc1def2", ("abc1def2", "1")), matchType: (Substring, Substring).self, ==) { - OneOrMore(.word, .reluctantly) + OneOrMore(.word, .reluctant) Capture(.digit) ZeroOrMore(.any) } - -#if os(macOS) - try XCTExpectFailure("'relucantCaptures()' API should only affect regex literals") { - try _testDSLCaptures( - ("abc1def2", ("abc1def2", "2")), - matchType: (Substring, Substring).self, ==) - { - Regex { - OneOrMore(.word) - Capture(.digit) - ZeroOrMore(.any) - }.reluctantQuantifiers() - } - } -#endif - + // Explicitly reluctant overrides default option try _testDSLCaptures( ("abc1def2", ("abc1def2", "1")), matchType: (Substring, Substring).self, ==) { - OneOrMore(.reluctantly) { + OneOrMore(.reluctant) { .word - } + }.repetitionBehavior(.possessive) Capture(.digit) ZeroOrMore(.any) } + // Default set to reluctant + try _testDSLCaptures( + ("abc1def2", ("abc1def2", "1")), + matchType: (Substring, Substring).self, ==) + { + Regex { + OneOrMore(.word) + Capture(.digit) + ZeroOrMore(.any) + }.repetitionBehavior(.reluctant) + } + // Default set to reluctant applies to regex syntax + try _testDSLCaptures( + ("abc1def2", ("abc1def2", "1")), + matchType: (Substring, Substring).self, ==) + { + try! Regex(#"\w+(\d).*"#, as: (Substring, Substring).self) + .repetitionBehavior(.reluctant) + } + // Explicitly possessive + try _testDSLCaptures( + ("aaaa", nil), + matchType: Substring.self, ==) + { + Regex { + OneOrMore("a", .possessive) + "a" + } + } + // Default set to possessive + try _testDSLCaptures( + ("aaaa", nil), + matchType: Substring.self, ==) + { + Regex { + OneOrMore("a") + "a" + }.repetitionBehavior(.possessive) + } + // More specific default set to eager + try _testDSLCaptures( + ("aaaa", ("aaaa", "aaa")), + matchType: (Substring, Substring).self, ==) + { + Regex { + Capture { + OneOrMore("a") + .repetitionBehavior(.eager) + } + OneOrMore("a") + }.repetitionBehavior(.possessive) + } + // More specific default set to reluctant + try _testDSLCaptures( + ("aaaa", ("aaaa", "a")), + matchType: (Substring, Substring).self, ==) + { + Regex { + Capture { + OneOrMore("a") + .repetitionBehavior(.reluctant) + } + OneOrMore("a") + }.repetitionBehavior(.possessive) + } + try _testDSLCaptures( ("abc1def2", "abc1def2"), matchType: Substring.self, ==) From 73a5ccf4b376ca484df5714537d201ea18fc6d5e Mon Sep 17 00:00:00 2001 From: Tina Liu <49205802+itingliu@users.noreply.github.com> Date: Fri, 22 Apr 2022 06:39:04 -0700 Subject: [PATCH 087/133] Add `wholeMatch` and `prefixMatch` (#286) Add the functions to string processing algorithms proposal and implement the change. Move the functions from `String` and `SubString` extensions to `BidirectionalCollection`. Add tests for `firstMatch`, `wholeMatch`, and `prefixMatch` that use a custom `BidirectionalCollection` type. --- .../Evolution/StringProcessingAlgorithms.md | 23 ++- .../Algorithms/Matching/FirstMatch.swift | 1 + Sources/_StringProcessing/Regex/Match.swift | 27 +-- Tests/RegexBuilderTests/CustomTests.swift | 161 ++++++++++++++++++ 4 files changed, 188 insertions(+), 24 deletions(-) diff --git a/Documentation/Evolution/StringProcessingAlgorithms.md b/Documentation/Evolution/StringProcessingAlgorithms.md index 8680ff75a..74416ae63 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -162,10 +162,11 @@ We also propose the following regex-powered algorithms as well as their generic |`replace(:with:subrange:maxReplacements)`| Replaces all occurrences of the sequence matching the given `RegexComponent` or sequence with a given collection | |`split(by:)`| Returns the longest possible subsequences of the collection around elements equal to the given separator | |`firstMatch(of:)`| Returns the first match of the specified `RegexComponent` within the collection | +|`wholeMatch(of:)`| Matches the specified `RegexComponent` in the collection as a whole | +|`prefixMatch(of:)`| Matches the specified `RegexComponent` against the collection at the beginning | |`matches(of:)`| Returns a collection containing all matches of the specified `RegexComponent` | - ## Detailed design ### `CustomMatchingRegexComponent` @@ -389,7 +390,7 @@ extension BidirectionalCollection where SubSequence == Substring { } ``` -#### First match +#### Match ```swift extension BidirectionalCollection where SubSequence == Substring { @@ -398,6 +399,16 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: The first match of `regex` in the collection, or `nil` if /// there isn't a match. public func firstMatch(of regex: R) -> RegexMatch? + + /// Match a regex in its entirety. + /// - Parameter r: The regex to match against. + /// - Returns: The match if there is one, or `nil` if none. + public func wholeMatch(of r: R) -> Regex.Match? + + /// Match part of the regex, starting at the beginning. + /// - Parameter r: The regex to match against. + /// - Returns: The match if there is one, or `nil` if none. + public func prefixMatch(of r: R) -> Regex.Match? } ``` @@ -473,7 +484,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` in `subrange` are replaced by `replacement`. public func replacing( - _ regex: R, + _ r: R, with replacement: Replacement, subrange: Range, maxReplacements: Int = .max @@ -489,7 +500,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. public func replacing( - _ regex: R, + _ r: R, with replacement: Replacement, maxReplacements: Int = .max ) -> Self where Replacement.Element == Element @@ -502,7 +513,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - maxReplacements: A number specifying how many occurrences of the /// sequence matching `regex` to replace. Default is `Int.max`. public mutating func replace( - _ regex: R, + _ r: R, with replacement: Replacement, maxReplacements: Int = .max ) where Replacement.Element == Element @@ -609,4 +620,4 @@ Trimming a string from both sides shares a similar story. For example, `"ababa". ### Future API -Some Python functions are not currently included in this proposal, such as trimming the suffix from a string/collection. This pitch aims to establish a pattern for using `RegexComponent` with string processing algorithms, so that further enhancement can to be introduced to the standard library easily in the future, and eventually close the gap between Swift and other popular scripting languages. +Some common string processing functions are not currently included in this proposal, such as trimming the suffix from a string/collection, and finding overlapping ranges of matched substrings. This pitch aims to establish a pattern for using `RegexComponent` with string processing algorithms, so that further enhancement can to be introduced to the standard library easily in the future, and eventually close the gap between Swift and other popular scripting languages. diff --git a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift index cb527f948..4342391af 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift @@ -39,6 +39,7 @@ extension BidirectionalCollection { extension BidirectionalCollection where SubSequence == Substring { @available(SwiftStdlib 5.7, *) + @_disfavoredOverload func firstMatch( of regex: R ) -> _MatchResult>? { diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 45b177867..e38af43f8 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -159,32 +159,23 @@ extension Regex { } @available(SwiftStdlib 5.7, *) -extension String { +extension BidirectionalCollection where SubSequence == Substring { + /// Match a regex in its entirety. + /// - Parameter r: The regex to match against. + /// - Returns: The match if there is one, or `nil` if none. public func wholeMatch( of r: R ) -> Regex.Match? { - try? r.regex.wholeMatch(in: self) + try? r.regex.wholeMatch(in: self[...].base) } + /// Match part of the regex, starting at the beginning. + /// - Parameter r: The regex to match against. + /// - Returns: The match if there is one, or `nil` if none. public func prefixMatch( of r: R ) -> Regex.Match? { - try? r.regex.prefixMatch(in: self) - } -} - -@available(SwiftStdlib 5.7, *) -extension Substring { - public func wholeMatch( - of r: R - ) -> Regex.Match? { - try? r.regex.wholeMatch(in: self) - } - - public func prefixMatch( - of r: R - ) -> Regex.Match? { - try? r.regex.prefixMatch(in: self) + try? r.regex.prefixMatch(in: self[...]) } } diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index bf4489a68..d17c3a142 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -133,6 +133,51 @@ func customTest( } } +// Test support +struct Concat : Equatable { + var wrapped: String + init(_ name: String, _ suffix: Int?) { + if let suffix = suffix { + wrapped = name + String(suffix) + } else { + wrapped = name + } + } +} + +extension Concat : Collection { + typealias Index = String.Index + typealias Element = String.Element + + var startIndex: Index { return wrapped.startIndex } + var endIndex: Index { return wrapped.endIndex } + + subscript(position: Index) -> Element { + return wrapped[position] + } + + func index(after i: Index) -> Index { + return wrapped.index(after: i) + } +} + +extension Concat: BidirectionalCollection { + typealias Indices = String.Indices + typealias SubSequence = String.SubSequence + + func index(before i: Index) -> Index { + return wrapped.index(before: i) + } + + var indices: Indices { + wrapped.indices + } + + subscript(bounds: Range) -> Substring { + Substring(wrapped[bounds]) + } +} + class CustomRegexComponentTests: XCTestCase { // TODO: Refactor below into more exhaustive, declarative // tests. @@ -467,4 +512,120 @@ class CustomRegexComponentTests: XCTestCase { ) } + + + func testMatchVarients() { + func customTest( + _ regex: Regex, + _ input: Concat, + expected: (wholeMatch: Match?, firstMatch: Match?, prefixMatch: Match?), + file: StaticString = #file, line: UInt = #line + ) { + let wholeResult = input.wholeMatch(of: regex)?.output + let firstResult = input.firstMatch(of: regex)?.output + let prefixResult = input.prefixMatch(of: regex)?.output + XCTAssertEqual(wholeResult, expected.wholeMatch, file: file, line: line) + XCTAssertEqual(firstResult, expected.firstMatch, file: file, line: line) + XCTAssertEqual(prefixResult, expected.prefixMatch, file: file, line: line) + } + + typealias CaptureMatch1 = (Substring, Int?) + func customTest( + _ regex: Regex, + _ input: Concat, + expected: (wholeMatch: CaptureMatch1?, firstMatch: CaptureMatch1?, prefixMatch: CaptureMatch1?), + file: StaticString = #file, line: UInt = #line + ) { + let wholeResult = input.wholeMatch(of: regex)?.output + let firstResult = input.firstMatch(of: regex)?.output + let prefixResult = input.prefixMatch(of: regex)?.output + XCTAssertEqual(wholeResult?.0, expected.wholeMatch?.0, file: file, line: line) + XCTAssertEqual(wholeResult?.1, expected.wholeMatch?.1, file: file, line: line) + + XCTAssertEqual(firstResult?.0, expected.firstMatch?.0, file: file, line: line) + XCTAssertEqual(firstResult?.1, expected.firstMatch?.1, file: file, line: line) + + XCTAssertEqual(prefixResult?.0, expected.prefixMatch?.0, file: file, line: line) + XCTAssertEqual(prefixResult?.1, expected.prefixMatch?.1, file: file, line: line) + } + + var regex = Regex { + OneOrMore(.digit) + } + + customTest(regex, Concat("amy", 2023), expected:(nil, "2023", nil)) // amy2023 + customTest(regex, Concat("amy2023", nil), expected:(nil, "2023", nil)) + customTest(regex, Concat("amy", nil), expected:(nil, nil, nil)) + customTest(regex, Concat("", 2023), expected:("2023", "2023", "2023")) // 2023 + customTest(regex, Concat("bob012b", 2023), expected:(nil, "012", nil)) // b012b2023 + customTest(regex, Concat("bob012b", nil), expected:(nil, "012", nil)) + customTest(regex, Concat("007bob", 2023), expected:(nil, "007", "007")) + customTest(regex, Concat("", nil), expected:(nil, nil, nil)) + + regex = Regex { + OneOrMore(CharacterClass("a"..."z")) + } + + customTest(regex, Concat("amy", 2023), expected:(nil, "amy", "amy")) // amy2023 + customTest(regex, Concat("amy", nil), expected:("amy", "amy", "amy")) + customTest(regex, Concat("amy2022-bob", 2023), expected:(nil, "amy", "amy")) // amy2023 + customTest(regex, Concat("", 2023), expected:(nil, nil, nil)) // 2023 + customTest(regex, Concat("bob012b", 2023), expected:(nil, "bob", "bob")) // b012b2023 + customTest(regex, Concat("bob012b", nil), expected:(nil, "bob", "bob")) + customTest(regex, Concat("007bob", 2023), expected:(nil, "bob", nil)) + customTest(regex, Concat("", nil), expected:(nil, nil, nil)) + + regex = Regex { + OneOrMore { + CharacterClass("A"..."Z") + OneOrMore(CharacterClass("a"..."z")) + Repeat(.digit, count: 2) + } + } + + customTest(regex, Concat("Amy12345", nil), expected:(nil, "Amy12", "Amy12")) + customTest(regex, Concat("Amy", 2023), expected:(nil, "Amy20", "Amy20")) + customTest(regex, Concat("Amy", 23), expected:("Amy23", "Amy23", "Amy23")) + customTest(regex, Concat("", 2023), expected:(nil, nil, nil)) // 2023 + customTest(regex, Concat("Amy23 Boba17", nil), expected:(nil, "Amy23", "Amy23")) + customTest(regex, Concat("amy23 Boba17", nil), expected:(nil, "Boba17", nil)) + customTest(regex, Concat("Amy23 boba17", nil), expected:(nil, "Amy23", "Amy23")) + customTest(regex, Concat("amy23 Boba", 17), expected:(nil, "Boba17", nil)) + customTest(regex, Concat("Amy23Boba17", nil), expected:("Amy23Boba17", "Amy23Boba17", "Amy23Boba17")) + customTest(regex, Concat("Amy23Boba", 17), expected:("Amy23Boba17", "Amy23Boba17", "Amy23Boba17")) + customTest(regex, Concat("23 Boba", 17), expected:(nil, "Boba17", nil)) + + let twoDigitRegex = Regex { + OneOrMore { + CharacterClass("A"..."Z") + OneOrMore(CharacterClass("a"..."z")) + Capture(Repeat(.digit, count: 2)) { Int($0) } + } + } + + customTest(twoDigitRegex, Concat("Amy12345", nil), expected: (nil, ("Amy12", 12), ("Amy12", 12))) + customTest(twoDigitRegex, Concat("Amy", 12345), expected: (nil, ("Amy12", 12), ("Amy12", 12))) + customTest(twoDigitRegex, Concat("Amy", 12), expected: (("Amy12", 12), ("Amy12", 12), ("Amy12", 12))) + customTest(twoDigitRegex, Concat("Amy23 Boba", 17), expected: (nil, firstMatch: ("Amy23", 23), prefixMatch: ("Amy23", 23))) + customTest(twoDigitRegex, Concat("amy23 Boba20", 23), expected:(nil, ("Boba20", 20), nil)) + customTest(twoDigitRegex, Concat("Amy23Boba17", nil), expected:(("Amy23Boba17", 17), ("Amy23Boba17", 17), ("Amy23Boba17", 17))) + customTest(twoDigitRegex, Concat("Amy23Boba", 17), expected:(("Amy23Boba17", 17), ("Amy23Boba17", 17), ("Amy23Boba17", 17))) + + let millennium = Regex { + CharacterClass("A"..."Z") + OneOrMore(CharacterClass("a"..."z")) + Capture { Repeat(.digit, count: 4) } transform: { v -> Int? in + guard let year = Int(v) else { return nil } + return year > 2000 ? year : nil + } + } + + customTest(millennium, Concat("Amy2025", nil), expected: (("Amy2025", 2025), ("Amy2025", 2025), ("Amy2025", 2025))) + customTest(millennium, Concat("Amy", 2025), expected: (("Amy2025", 2025), ("Amy2025", 2025), ("Amy2025", 2025))) + customTest(millennium, Concat("Amy1995", nil), expected: (("Amy1995", nil), ("Amy1995", nil), ("Amy1995", nil))) + customTest(millennium, Concat("Amy", 1995), expected: (("Amy1995", nil), ("Amy1995", nil), ("Amy1995", nil))) + customTest(millennium, Concat("amy2025", nil), expected: (nil, nil, nil)) + customTest(millennium, Concat("amy", 2025), expected: (nil, nil, nil)) + } } + From 3e2160c88fd2577e93f93ea99fd0900f0d44cf7b Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Fri, 22 Apr 2022 07:49:58 -0600 Subject: [PATCH 088/133] Update local proposal copies (#317) * Bring run time proposal up to speed * Update repo doc to be in line with SE --- .../RegexSyntaxRunTimeConstruction.md | 25 +++++++++++++-- Documentation/Evolution/RegexTypeOverview.md | 31 +++++++++++++++---- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md index 1a868aa04..5c9fa6c59 100644 --- a/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md +++ b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md @@ -1,7 +1,12 @@ # Regex Syntax and Run-time Construction -- Authors: [Hamish Knight](https://github.com/hamishknight), [Michael Ilseman](https://github.com/milseman) +* Proposal: [SE-NNNN](NNNN-filename.md) +* Authors: [Hamish Knight](https://github.com/hamishknight), [Michael Ilseman](https://github.com/milseman) +* Review Manager: [Ben Cohen](https://github.com/airspeedswift) +* Status: **Awaiting review** +* Implementation: https://github.com/apple/swift-experimental-string-processing + * Available in nightly toolchain snapshots with `import _StringProcessing` ## Introduction @@ -81,11 +86,11 @@ We propose initializers to declare and compile a regex from syntax. Upon failure ```swift extension Regex { /// Parse and compile `pattern`, resulting in a strongly-typed capture list. - public init(compiling pattern: String, as: Output.Type = Output.self) throws + public init(_ pattern: String, as: Output.Type = Output.self) throws } extension Regex where Output == AnyRegexOutput { /// Parse and compile `pattern`, resulting in an existentially-typed capture list. - public init(compiling pattern: String) throws + public init(_ pattern: String) throws } ``` @@ -156,6 +161,20 @@ extension Regex.Match where Output == AnyRegexOutput { } ``` +We propose adding API to query and access captures by name in an existentially typed regex match: + +```swift +extension Regex.Match where Output == AnyRegexOutput { + /// If a named-capture with `name` is present, returns its value. Otherwise `nil`. + public subscript(_ name: String) -> AnyRegexOutput.Element? { get } +} + +extension AnyRegexOutput { + /// If a named-capture with `name` is present, returns its value. Otherwise `nil`. + public subscript(_ name: String) -> AnyRegexOutput.Element? { get } +} +``` + The rest of this proposal will be a detailed and exhaustive definition of our proposed regex syntax.
Grammar Notation diff --git a/Documentation/Evolution/RegexTypeOverview.md b/Documentation/Evolution/RegexTypeOverview.md index 9fd369dbf..6eed648f0 100644 --- a/Documentation/Evolution/RegexTypeOverview.md +++ b/Documentation/Evolution/RegexTypeOverview.md @@ -1,6 +1,11 @@ # Regex Type and Overview -- Authors: [Michael Ilseman](https://github.com/milseman) +* Proposal: [SE-0350](0350-regex-type-overview.md) +* Authors: [Michael Ilseman](https://github.com/milseman) +* Review Manager: [Ben Cohen](https://github.com/airspeedswift) +* Status: **Active Review (4 - 28 April 2022)** +* Implementation: https://github.com/apple/swift-experimental-string-processing + * Available in nightly toolchain snapshots with `import _StringProcessing` ## Introduction @@ -207,7 +212,7 @@ func processEntry(_ line: String) -> Transaction? { // amount: Substring // )> - guard let match = regex.matchWhole(line), + guard let match = regex.wholeMatch(line), let kind = Transaction.Kind(match.kind), let date = try? Date(String(match.date), strategy: dateParser), let amount = try? Decimal(String(match.amount), format: decimalParser) @@ -384,21 +389,25 @@ extension Regex.Match { // Run-time compilation interfaces extension Regex { /// Parse and compile `pattern`, resulting in a strongly-typed capture list. - public init(compiling pattern: String, as: Output.Type = Output.self) throws + public init(_ pattern: String, as: Output.Type = Output.self) throws } extension Regex where Output == AnyRegexOutput { /// Parse and compile `pattern`, resulting in an existentially-typed capture list. - public init(compiling pattern: String) throws + public init(_ pattern: String) throws } ``` +### Cancellation + +Regex is somewhat different from existing standard library operations in that regex processing can be a long-running task. +For this reason regex algorithms may check if the parent task has been cancelled and end execution. + ### On severability and related proposals The proposal split presented is meant to aid focused discussion, while acknowledging that each is interconnected. The boundaries between them are not completely cut-and-dry and could be refined as they enter proposal phase. Accepting this proposal in no way implies that all related proposals must be accepted. They are severable and each should stand on their own merit. - ## Source compatibility Everything in this proposal is additive. Regex delimiters may have their own source compatibility impact, which is discussed in that proposal. @@ -488,6 +497,16 @@ The generic parameter `Output` is proposed to contain both the whole match (the The biggest issue with this alternative design is that the numbering of `Captures` elements misaligns with the numbering of captures in textual regexes, where backreference `\0` refers to the entire match and captures start at `\1`. This design would sacrifice familarity and have the pitfall of introducing off-by-one errors. +### Encoding `Regex`es into the type system + +During the initial review period the following comment was made: + +> I think the goal should be that, at least for regex literals (and hopefully for the DSL to some extent), one day we might not even need a bytecode or interpreter. I think the ideal case is if each literal was its own function or type that gets generated and optimised as if you wrote it in Swift. + +This is an approach that has been tried a few times in a few different languages (including by a few members of the Swift Standard Library and Core teams), and while it can produce attractive microbenchmarks, it has almost always proved to be a bad idea at the macro scale. In particular, even if we set aside witness tables and other associated swift generics overhead, optimizing a fixed pipeline for each pattern you want to match causes significant codesize expansion when there are multiple patterns in use, as compared to a more flexible byte code interpreter. A bytecode interpreter makes better use of instruction caches and memory, and can also benefit from micro architectural resources that are shared across different patterns. There is a tradeoff w.r.t. branch prediction resources, where separately compiled patterns may have more decisive branch history data, but a shared bytecode engine has much more data to use; this tradeoff tends to fall on the side of a bytecode engine, but it does not always do so. + +It should also be noted that nothing prevents AOT or JIT compiling of the bytecode if we believe it will be advantageous, but compiling or interpreting arbitrary Swift code at runtime is rather more unattractive, since both the type system and language are undecidable. Even absent this rationale, we would probably not encode regex programs directly into the type system simply because it is unnecessarily complex. + ### Future work: static optimization and compilation Swift's support for static compilation is still developing, and future work here is leveraging that to compile regex when profitable. Many regex describe simple [DFAs](https://en.wikipedia.org/wiki/Deterministic_finite_automaton) and can be statically compiled into very efficient programs. Full static compilation needs to be balanced with code size concerns, as a matching-specific bytecode is typically far smaller than a corresponding program (especially since the bytecode interpreter is shared). @@ -551,4 +570,4 @@ Regexes are often used for tokenization and tokens can be represented with Swift --> -[pitches]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/ProposalOverview.md +[pitches]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/ProposalOverview.md \ No newline at end of file From 53acbb2fc517c5fcb58267e0b9a7daef0c89d003 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Fri, 22 Apr 2022 10:02:20 -0600 Subject: [PATCH 089/133] Update ProposalOverview.md --- Documentation/Evolution/ProposalOverview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Evolution/ProposalOverview.md b/Documentation/Evolution/ProposalOverview.md index 4346932b5..45712ea1f 100644 --- a/Documentation/Evolution/ProposalOverview.md +++ b/Documentation/Evolution/ProposalOverview.md @@ -19,7 +19,7 @@ Covers the result builder approach and basic API. ## Run-time Regex Construction -- [Pitch](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md) +- [Pitch](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md), [Thread](https://forums.swift.org/t/pitch-2-regex-syntax-and-run-time-construction/56624) - (old) Pitch thread: [Regex Syntax](https://forums.swift.org/t/pitch-regex-syntax/55711) + Brief: Syntactic superset of PCRE2, Oniguruma, ICU, UTS\#18, etc. From b057c4e7415516d2fc57ff7fbdae95bd5f7a4d3e Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Fri, 22 Apr 2022 10:03:09 -0600 Subject: [PATCH 090/133] Update ProposalOverview.md --- Documentation/Evolution/ProposalOverview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Evolution/ProposalOverview.md b/Documentation/Evolution/ProposalOverview.md index 45712ea1f..8fa6096e8 100644 --- a/Documentation/Evolution/ProposalOverview.md +++ b/Documentation/Evolution/ProposalOverview.md @@ -27,7 +27,7 @@ Covers the "interior" syntax, extended syntaxes, run-time construction of a rege ## Regex Literals -- [Draft](https://github.com/apple/swift-experimental-string-processing/pull/187) +- [Draft](https://github.com/apple/swift-experimental-string-processing/pull/187), [Thread](https://forums.swift.org/t/pitch-2-regex-literals/56736) - (Old) original pitch: + [Thread](https://forums.swift.org/t/pitch-regular-expression-literals/52820) + [Update](https://forums.swift.org/t/pitch-regular-expression-literals/52820/90) From 8dd8470fb75cce92a1f9204b96f2fce93d296b95 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 22 Apr 2022 11:26:58 -0500 Subject: [PATCH 091/133] Unicode for String Processing proposal (#257) --- Documentation/Evolution/CharacterClasses.md | 503 ---------- Documentation/Evolution/ProposalOverview.md | 6 +- .../Evolution/UnicodeForStringProcessing.md | 872 ++++++++++++++++++ Tests/RegexBuilderTests/RegexDSLTests.swift | 8 + 4 files changed, 883 insertions(+), 506 deletions(-) delete mode 100644 Documentation/Evolution/CharacterClasses.md create mode 100644 Documentation/Evolution/UnicodeForStringProcessing.md diff --git a/Documentation/Evolution/CharacterClasses.md b/Documentation/Evolution/CharacterClasses.md deleted file mode 100644 index c9ffcbc95..000000000 --- a/Documentation/Evolution/CharacterClasses.md +++ /dev/null @@ -1,503 +0,0 @@ -# Character Classes for String Processing - -- **Authors:** [Nate Cook](https://github.com/natecook1000), [Michael Ilseman](https://github.com/milseman) -- **Status:** Draft pitch - -## Introduction - -[Declarative String Processing Overview][overview] presents regex-powered matching broadly, without details concerning syntax and semantics, leaving clarification to subsequent pitches. [Regular Expression Literals][literals] presents more details on regex _syntax_ such as delimiters and PCRE-syntax innards, but explicitly excludes discussion of regex _semantics_. This pitch and discussion aims to address a targeted subset of regex semantics: definitions of character classes. We propose a comprehensive treatment of regex character class semantics in the context of existing and newly proposed API directly on `Character` and `Unicode.Scalar`. - -Character classes in regular expressions include metacharacters like `\d` to match a digit, `\s` to match whitespace, and `.` to match any character. Individual literal characters can also be thought of as character classes, as they at least match themselves, and, in case-insensitive matching, their case-toggled counterpart. For the purpose of this work, then, we consider a *character class* to be any part of a regular expression literal that can match an actual component of a string. - -## Motivation - -Operating over classes of characters is a vital component of string processing. Swift's `String` provides, by default, a view of `Character`s or [extended grapheme clusters][graphemes] whose comparison honors [Unicode canonical equivalence][canoneq]. - -```swift -let str = "Cafe\u{301}" // "Café" -str == "Café" // true -str.dropLast() // "Caf" -str.last == "é" // true (precomposed e with acute accent) -str.last == "e\u{301}" // true (e followed by composing acute accent) -``` - -Unicode leaves all interpretation of grapheme clusters up to implementations, which means that Swift needs to define any semantics for its own usage. Since other regex engines operate, at most, at the semantics level of Unicode scalar values, there is little to no prior art to consult. - -
Other engines - -Character classes in other languages match at either the Unicode scalar value level, or even the code unit level, instead of recognizing grapheme clusters as characters. When matching the `.` character class, other languages will only match the first part of an `"e\u{301}"` grapheme cluster. Some languages, like Perl, Ruby, and Java, support an additional `\X` metacharacter, which explicitly represents a single grapheme cluster. - -| Matching `"Cafe\u{301}"` | Pattern: `^Caf.` | Remaining | Pattern: `^Caf\X` | Remaining | -|---|---|---|---|---| -| C#, Rust, Go | `"Cafe"` | `"´"` | n/a | n/a | -| NSString, Java, Ruby, Perl | `"Cafe"` | `"´"` | `"Café"` | `""` | - -Other than Java's `CANON_EQ` option, the vast majority of other languages and engines are not capable of comparing with canonical equivalence. - -
- -[SE-0211 Unicode Scalar Properties][scalarprops] added basic building blocks for classification of scalars by surfacing Unicode data from the [UCD][ucd]. [SE-0221: Character Properties][charprops] defined grapheme-cluster semantics for Swift for a subset of these. But, many classifications used in string processing are combinations of scalar properties or ad-hoc listings, and as such are not present today in Swift. - -Regardless of any syntax or underlying formalism, classifying characters is a worthy and much needed addition to the Swift standard library. We believe our thorough treatment of every character class found across many popular regex engines gives Swift a solid semantic basis. - -## Proposed Solution - -This pitch is narrowly scoped to Swift definitions of character classes found in regexes. For each character class, we propose: - -- A name for use in API -- A `Character` API, by extending Unicode scalar definitions to grapheme clusters -- A `Unicode.Scalar` API with modern Unicode definitions -- If applicable, a `Unicode.Scalar` API for notable standards like POSIX - -We're proposing what we believe to be the Swiftiest definitions using [Unicode's guidance][uts18] for `Unicode.Scalar` and extending this to grapheme clusters using `Character`'s existing [rationale][charpropsrationale]. - -
Broad language/engine survey - -For these definitions, we cross-referenced Unicode's [UTS\#18][uts18] with a broad survey of existing languages and engines. We found that while these all support a subset of UTS\#18, each language or framework implements a slightly different subset. The following table shows some of the variations: - -| Language/Framework | Dot (`.`) matches | Supports `\X` | Canonical Equivalence | `\d` matches FULL WIDTH digit | -|------------------------------|----------------------------------------------------|---------------|---------------------------|-------------------------------| -| [ECMAScript][ecmascript] | UTF16 code unit (Unicode scalar in Unicode mode) | no | no | no | -| [Perl][perl] / [PCRE][pcre] | UTF16 code unit, (Unicode scalar in Unicode mode) | yes | no | no | -| [Python3][python] | Unicode scalar | no | no | yes | -| [Raku][raku] | Grapheme cluster | n/a | strings always normalized | yes | -| [Ruby][ruby] | Unicode scalar | yes | no | no | -| [Rust][rust] | Unicode scalar | no | no | no | -| [C#][csharp] | UTF16 code unit | no | no | yes | -| [Java][java] | Unicode scalar | yes | Only in CANON_EQ mode | no | -| [Go][go] | Unicode scalar | no | no | no | -| [`NSRegularExpression`][icu] | Unicode scalar | yes | no | yes | - -We are still in the process of evaluating [C++][cplusplus], [RE2][re2], and [Oniguruma][oniguruma]. - -
- -## Detailed Design - -### Literal characters - -A literal character (such as `a`, `é`, or `한`) in a regex literal matches that particular character or code sequence. When matching at the semantic level of `Unicode.Scalar`, it should match the literal sequence of scalars. When matching at the semantic level of `Character`, it should match `Character`-by-`Character`, honoring Unicode canonical equivalence. - -We are not proposing new API here as this is already handled by `String` and `String.UnicodeScalarView`'s conformance to `Collection`. - -### Unicode values: `\u`, `\U`, `\x` - -Metacharacters that begin with `\u`, `\U`, or `\x` match a character with the specified Unicode scalar values. We propose these be treated exactly the same as literals. - -### Match any: `.`, `\X` - -The dot metacharacter matches any single character or element. Depending on options and modes, it may exclude newlines. - -`\X` matches any grapheme cluster (`Character`), even when the regular expression is otherwise matching at semantic level of `Unicode.Scalar`. - -We are not proposing new API here as this is already handled by collection conformances. - -While we would like for the stdlib to have grapheme-breaking API over collections of `Unicode.Scalar`, that is a separate discussion and out-of-scope for this pitch. - -### Decimal digits: `\d`,`\D` - -We propose `\d` be named "decimalDigit" with the following definitions: - -```swift -extension Character { - /// A Boolean value indicating whether this character represents - /// a decimal digit. - /// - /// Decimal digits are comprised of a single Unicode scalar that has a - /// `numericType` property equal to `.decimal`. This includes the digits - /// from the ASCII range, from the _Halfwidth and Fullwidth Forms_ Unicode - /// block, as well as digits in some scripts, like `DEVANAGARI DIGIT NINE` - /// (U+096F). - /// - /// Decimal digits are a subset of whole numbers, see `isWholeNumber`. - /// - /// To get the character's value, use the `decimalDigitValue` property. - public var isDecimalDigit: Bool { get } - - /// The numeric value this character represents, if it is a decimal digit. - /// - /// Decimal digits are comprised of a single Unicode scalar that has a - /// `numericType` property equal to `.decimal`. This includes the digits - /// from the ASCII range, from the _Halfwidth and Fullwidth Forms_ Unicode - /// block, as well as digits in some scripts, like `DEVANAGARI DIGIT NINE` - /// (U+096F). - /// - /// Decimal digits are a subset of whole numbers, see `wholeNumberValue`. - /// - /// let chars: [Character] = ["1", "९", "A"] - /// for ch in chars { - /// print(ch, "-->", ch.decimalDigitValue) - /// } - /// // Prints: - /// // 1 --> Optional(1) - /// // ९ --> Optional(9) - /// // A --> nil - public var decimalDigitValue: Int? { get } - -} - -extension Unicode.Scalar { - /// A Boolean value indicating whether this scalar is considered - /// a decimal digit. - /// - /// Any Unicode scalar that has a `numericType` property equal to `.decimal` - /// is considered a decimal digit. This includes the digits from the ASCII - /// range, from the _Halfwidth and Fullwidth Forms_ Unicode block, as well - /// as digits in some scripts, like `DEVANAGARI DIGIT NINE` (U+096F). - public var isDecimalDigit: Bool { get } -} -``` - -`\D` matches the inverse of `\d`. - -*TBD*: [SE-0221: Character Properties][charprops] did not define equivalent API on `Unicode.Scalar`, as it was itself an extension of single `Unicode.Scalar.Properties`. Since we're defining additional classifications formed from algebraic formulations of properties, it may make sense to put API such as `decimalDigitValue` on `Unicode.Scalar` as well as back-porting other API from `Character` (e.g. `hexDigitValue`). We'd like to discuss this with the community. - -*TBD*: `Character.isHexDigit` is currently constrained to the subset of decimal digits that are followed by encodings of Latin letters `A-F` in various forms (all 6 of them... thanks Unicode). We could consider extending this to be a superset of `isDecimalDigit` by allowing and producing values for all decimal digits, one would just have to use the Latin letters to refer to values greater than `9`. We'd like to discuss this with the community. - -_
Rationale_ - -Unicode's recommended definition for `\d` is its [numeric type][numerictype] of "Decimal" in contrast to "Digit". It is specifically restricted to sets of ascending contiguously-encoded scalars in a decimal radix positional numeral system. Thus, it excludes "digits" such as superscript numerals from its [definition][derivednumeric] and is a proper subset of `Character.isWholeNumber`. - -We interpret Unicode's definition of the set of scalars, especially its requirement that scalars be encoded in ascending chains, to imply that this class is restricted to scalars which meaningfully encode base-10 digits. Thus, we choose to make this Character property _restrictive_, similar to `isHexDigit` and `isWholeNumber` and provide a way to access this value. - -It's possible we might add future properties to differentiate Unicode's non-decimal digits, but that is outside the scope of this pitch. - -
- -### Word characters: `\w`, `\W` - -We propose `\w` be named "word character" with the following definitions: - -```swift -extension Character { - /// A Boolean value indicating whether this character is considered - /// a "word" character. - /// - /// See `Unicode.Scalar.isWordCharacter`. - public var isWordCharacter: Bool { get } -} - -extension Unicode.Scalar { - /// A Boolean value indicating whether this scalar is considered - /// a "word" character. - /// - /// Any Unicode scalar that has one of the Unicode properties - /// `Alphabetic`, `Digit`, or `Join_Control`, or is in the - /// general category `Mark` or `Connector_Punctuation`. - public var isWordCharacter: Bool { get } -} -``` - -`\W` matches the inverse of `\w`. - -_
Rationale_ - -Word characters include more than letters, and we went with Unicode's recommended scalar semantics. We extend to grapheme clusters similarly to `Character.isLetter`, that is, subsequent (combining) scalars do not change the word-character-ness of the grapheme cluster. - -
- -### Whitespace and newlines: `\s`, `\S` (plus `\h`, `\H`, `\v`, `\V`, and `\R`) - -We propose `\s` be named "whitespace" with the following definitions: - -```swift -extension Unicode.Scalar { - /// A Boolean value indicating whether this scalar is considered - /// whitespace. - /// - /// All Unicode scalars with the derived `White_Space` property are - /// considered whitespace, including: - /// - /// - `CHARACTER TABULATION` (U+0009) - /// - `LINE FEED (LF)` (U+000A) - /// - `LINE TABULATION` (U+000B) - /// - `FORM FEED (FF)` (U+000C) - /// - `CARRIAGE RETURN (CR)` (U+000D) - /// - `NEWLINE (NEL)` (U+0085) - public var isWhitespace: Bool { get } -} -``` - -This definition matches the value of the existing `Unicode.Scalar.Properties.isWhitespace` property. Note that `Character.isWhitespace` already exists with the desired semantics, which is a grapheme cluster that begins with a whitespace Unicode scalar. - -We propose `\h` be named "horizontalWhitespace" with the following definitions: - -```swift -extension Character { - /// A Boolean value indicating whether this character is considered - /// horizontal whitespace. - /// - /// All characters with an initial Unicode scalar in the general - /// category `Zs`/`Space_Separator`, or the control character - /// `CHARACTER TABULATION` (U+0009), are considered horizontal - /// whitespace. - public var isHorizontalWhitespace: Bool { get } -} - -extension Unicode.Scalar { - /// A Boolean value indicating whether this scalar is considered - /// horizontal whitespace. - /// - /// All Unicode scalars with the general category - /// `Zs`/`Space_Separator`, along with the control character - /// `CHARACTER TABULATION` (U+0009), are considered horizontal - /// whitespace. - public var isHorizontalWhitespace: Bool { get } -} -``` - -We propose `\v` be named "verticalWhitespace" with the following definitions: - - -```swift -extension Character { - /// A Boolean value indicating whether this scalar is considered - /// vertical whitespace. - /// - /// All characters with an initial Unicode scalar in the general - /// category `Zl`/`Line_Separator`, or the following control - /// characters, are considered vertical whitespace (see below) - public var isVerticalWhitespace: Bool { get } -} - -extension Unicode.Scalar { - /// A Boolean value indicating whether this scalar is considered - /// vertical whitespace. - /// - /// All Unicode scalars with the general category - /// `Zl`/`Line_Separator`, along with the following control - /// characters, are considered vertical whitespace: - /// - /// - `LINE FEED (LF)` (U+000A) - /// - `LINE TABULATION` (U+000B) - /// - `FORM FEED (FF)` (U+000C) - /// - `CARRIAGE RETURN (CR)` (U+000D) - /// - `NEWLINE (NEL)` (U+0085) - public var isVerticalWhitespace: Bool { get } -} -``` - -Note that `Character.isNewline` already exists with the definition [required][lineboundary] by UTS\#18. *TBD:* Should we backport to `Unicode.Scalar`? - -`\S`, `\H`, and `\V` match the inverse of `\s`, `\h`, and `\v`, respectively. - -We propose `\R` include "verticalWhitespace" above with detection (and consumption) of the CR-LF sequence when applied to `Unicode.Scalar`. It is equivalent to `Character.isVerticalWhitespace` when applied to `Character`s. - -We are similarly not proposing any new API for `\R` until the stdlib has grapheme-breaking API over `Unicode.Scalar`. - -_
Rationale_ - -Note that "whitespace" is a term-of-art and is not correlated with visibility, which is a completely separate concept. - -We use Unicode's recommended scalar semantics for horizontal whitespace and extend that to grapheme semantics similarly to `Character.isWhitespace`. - -We use ICU's definition for vertical whitespace, similarly extended to grapheme clusters. - -
- -### Control characters: `\t`, `\r`, `\n`, `\f`, `\0`, `\e`, `\a`, `\b`, `\cX` - -We propose the following names and meanings for these escaped literals representing specific control characters: - -```swift -extension Character { - /// A horizontal tab character, `CHARACTER TABULATION` (U+0009). - public static var tab: Character { get } - - /// A carriage return character, `CARRIAGE RETURN (CR)` (U+000D). - public static var carriageReturn: Character { get } - - /// A line feed character, `LINE FEED (LF)` (U+000A). - public static var lineFeed: Character { get } - - /// A form feed character, `FORM FEED (FF)` (U+000C). - public static var formFeed: Character { get } - - /// A NULL character, `NUL` (U+0000). - public static var nul: Character { get } - - /// An escape control character, `ESC` (U+001B). - public static var escape: Character { get } - - /// A bell character, `BEL` (U+0007). - public static var bell: Character { get } - - /// A backspace character, `BS` (U+0008). - public static var backspace: Character { get } - - /// A combined carriage return and line feed as a single character denoting - // end-of-line. - public static var carriageReturnLineFeed: Character { get } - - /// Returns a control character with the given value, Control-`x`. - /// - /// This method returns a value only when you pass a letter in - /// the ASCII range as `x`: - /// - /// if let ch = Character.control("G") { - /// print("'ch' is a bell character", ch == Character.bell) - /// } else { - /// print("'ch' is not a control character") - /// } - /// // Prints "'ch' is a bell character: true" - /// - /// - Parameter x: An upper- or lowercase letter to derive - /// the control character from. - /// - Returns: Control-`x` if `x` is in the pattern `[a-zA-Z]`; - /// otherwise, `nil`. - public static func control(_ x: Unicode.Scalar) -> Character? -} - -extension Unicode.Scalar { - /// Same as above, producing Unicode.Scalar, except for CR-LF... -} -``` - -We also propose `isControl` properties with the following definitions: - -```swift -extension Character { - /// A Boolean value indicating whether this character represents - /// a control character. - /// - /// Control characters are a single Unicode scalar with the - /// general category `Cc`/`Control` or the CR-LF pair (`\r\n`). - public var isControl: Bool { get } -} - -extension Unicode.Scalar { - /// A Boolean value indicating whether this scalar represents - /// a control character. - /// - /// Control characters have the general category `Cc`/`Control`. - public var isControl: Bool { get } -} -``` - -*TBD*: Should we have a CR-LF static var on `Unicode.Scalar` that produces a value of type `Character`? - - -_
Rationale_ - -This approach simplifies the use of some common control characters, while making the rest available through a method call. - -
- - - -### Unicode named values and properties: `\N`, `\p`, `\P` - -`\N{NAME}` matches a Unicode scalar value with the specified name. `\p{PROPERTY}` and `\p{PROPERTY=VALUE}` match a Unicode scalar value with the given Unicode property (and value, if given). - -While most Unicode-defined properties can only match at the Unicode scalar level, some are defined to match an extended grapheme cluster. For example, `/\p{RGI_Emoji_Flag_Sequence}/` will match any flag emoji character, which are composed of two Unicode scalar values. - -`\P{...}` matches the inverse of `\p{...}`. - -Most of this is already present inside `Unicode.Scalar.Properties`, and we propose to round it out with anything missing, e.g. script and script extensions. (API is _TBD_, still working on it.) - -Even though we are not proposing any `Character`-based API, we'd like to discuss with the community whether or how to extend them to grapheme clusters. Some options: - -- Forbid in any grapheme-cluster semantic mode -- Match only single-scalar grapheme clusters with the given property -- Match any grapheme cluster that starts with the given property -- Something more-involved such as per-property reasoning - - -### POSIX character classes: `[:NAME:]` - -We propose that POSIX character classes be prefixed with "posix" in their name with APIs for testing membership of `Character`s and `Unicode.Scalar`s. `Unicode.Scalar.isASCII` and `Character.isASCII` already exist and can satisfy `[:ascii:]`, and can be used in combination with new members like `isDigit` to represent individual POSIX character classes. Alternatively, we could introduce an option-set-like `POSIXCharacterClass` and `func isPOSIX(_:POSIXCharacterClass)` since POSIX is a fully defined standard. This would cut down on the amount of API noise directly visible on `Character` and `Unicode.Scalar` significantly. We'd like some discussion the the community here, noting that this will become clearer as more of the string processing overview takes shape. - -POSIX's character classes represent concepts that we'd like to define at all semantic levels. We propose the following definitions, some of which are covered elsewhere in this pitch and some of which already exist today. Some Character definitions are *TBD* and we'd like more discussion with the community. - - -| POSIX class | API name | `Character` | `Unicode.Scalar` | POSIX mode value | -|-------------|----------------------|-----------------------|-------------------------------|-------------------------------| -| `[:lower:]` | lowercase | (exists) | `\p{Lowercase}` | `[a-z]` | -| `[:upper:]` | uppercase | (exists) | `\p{Uppercase}` | `[A-Z]` | -| `[:alpha:]` | alphabetic | (exists: `.isLetter`) | `\p{Alphabetic}` | `[A-Za-z]` | -| `[:alnum:]` | alphaNumeric | TBD | `[\p{Alphabetic}\p{Decimal}]` | `[A-Za-z0-9]` | -| `[:word:]` | wordCharacter | (pitched) | (pitched) | `[[:alnum:]_]` | -| `[:digit:]` | decimalDigit | (pitched) | (pitched) | `[0-9]` | -| `[:xdigit:]`| hexDigit | (exists) | `\p{Hex_Digit}` | `[0-9A-Fa-f]` | -| `[:punct:]` | punctuation | (exists) | (port from `Character`) | `[-!"#%&'()*,./:;?@[\\\]_{}]` | -| `[:blank:]` | horizontalWhitespace | (pitched) | (pitched) | `[ \t]` | -| `[:space:]` | whitespace | (exists) | `\p{Whitespace}` | `[ \t\n\r\f\v]` | -| `[:cntrl:]` | control | (pitched) | (pitched) | `[\x00-\x1f\x7f]` | -| `[:graph:]` | TBD | TBD | TBD | `[^ [:cntrl:]]` | -| `[:print:]` | TBD | TBD | TBD | `[[:graph:] ]` | - - -### Custom classes: `[...]` - -We propose that custom classes function just like set union. We propose that ranged-based custom character classes function just like `ClosedRange`. Thus, we are not proposing any additional API. - -That being said, providing grapheme cluster semantics is simultaneously obvious and tricky. A direct extension treats `[a-f]` as equivalent to `("a"..."f").contains()`. Strings (and thus Characters) are ordered for the purposes of efficiently maintaining programming invariants while honoring Unicode canonical equivalence. This ordering is _consistent_ but [linguistically meaningless][meaningless] and subject to implementation details such as whether we choose to normalize under NFC or NFD. - -```swift -let c: ClosedRange = "a"..."f" -c.contains("e") // true -c.contains("g") // false -c.contains("e\u{301}") // false, NFC uses precomposed é -c.contains("e\u{305}") // true, there is no precomposed e̅ -``` - -We will likely want corresponding `RangeExpression`-based API in the future and keeping consistency with ranges is important. - -We would like to discuss this problem with the community here. Even though we are not addressing regex literals specifically in this thread, it makes sense to produce suggestions for compilation errors or warnings. - -Some options: - -- Do nothing, embrace emergent behavior -- Warn/error for _any_ character class ranges -- Warn/error for character class ranges outside of a quasi-meaningful subset (e.g. ACII, albeit still has issues above) -- Warn/error for multiple-scalar grapheme clusters (albeit still has issues above) - - - -## Future Directions - -### Future API - -Library-extensible pattern matching will necessitate more types, protocols, and API in the future, many of which may involve character classes. This pitch aims to define names and semantics for exactly these kinds of API now, so that they can slot in naturally. - -### More classes or custom classes - -Future API might express custom classes or need more built-in classes. This pitch aims to establish rationale and precedent for a large number of character classes in Swift, serving as a basis that can be extended. - -### More lenient conversion APIs - -The proposed semantics for matching "digits" are broader than what the existing `Int(_:radix:)?` initializer accepts. It may be useful to provide additional initializers that can understand the whole breadth of characters matched by `\d`, or other related conversions. - - - - -[literals]: https://forums.swift.org/t/pitch-regular-expression-literals/52820 -[overview]: https://forums.swift.org/t/declarative-string-processing-overview/52459 -[charprops]: https://github.com/apple/swift-evolution/blob/master/proposals/0221-character-properties.md -[charpropsrationale]: https://github.com/apple/swift-evolution/blob/master/proposals/0221-character-properties.md#detailed-semantics-and-rationale -[canoneq]: https://www.unicode.org/reports/tr15/#Canon_Compat_Equivalence -[graphemes]: https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries -[meaningless]: https://forums.swift.org/t/declarative-string-processing-overview/52459/121 -[scalarprops]: https://github.com/apple/swift-evolution/blob/master/proposals/0211-unicode-scalar-properties.md -[ucd]: https://www.unicode.org/reports/tr44/tr44-28.html -[numerictype]: https://www.unicode.org/reports/tr44/#Numeric_Type -[derivednumeric]: https://www.unicode.org/Public/UCD/latest/ucd/extracted/DerivedNumericType.txt - - -[uts18]: https://unicode.org/reports/tr18/ -[proplist]: https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt -[pcre]: https://www.pcre.org/current/doc/html/pcre2pattern.html -[perl]: https://perldoc.perl.org/perlre -[raku]: https://docs.raku.org/language/regexes -[rust]: https://docs.rs/regex/1.5.4/regex/ -[python]: https://docs.python.org/3/library/re.html -[ruby]: https://ruby-doc.org/core-2.4.0/Regexp.html -[csharp]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference -[icu]: https://unicode-org.github.io/icu/userguide/strings/regexp.html -[posix]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html -[oniguruma]: https://www.cuminas.jp/sdk/regularExpression.html -[go]: https://pkg.go.dev/regexp/syntax@go1.17.2 -[cplusplus]: https://www.cplusplus.com/reference/regex/ECMAScript/ -[ecmascript]: https://262.ecma-international.org/12.0/#sec-pattern-semantics -[re2]: https://github.com/google/re2/wiki/Syntax -[java]: https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html diff --git a/Documentation/Evolution/ProposalOverview.md b/Documentation/Evolution/ProposalOverview.md index 8fa6096e8..f3c3ac6d1 100644 --- a/Documentation/Evolution/ProposalOverview.md +++ b/Documentation/Evolution/ProposalOverview.md @@ -43,13 +43,13 @@ Introduces `CustomMatchingRegexComponent`, which is a monadic-parser style inter ## Unicode for String Processing -- Draft: TBD +- [Draft](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/UnicodeForStringProcessing.md) - (Old) [Character class definitions](https://forums.swift.org/t/pitch-character-classes-for-string-processing/52920) Covers three topics: -- Proposes literal and DSL API for library-defined character classes, Unicode scripts and properties, and custom character classes. -- Proposes literal and DSL API for options that affect matching behavior. +- Proposes regex syntax and `RegexBuilder` API for options that affect matching behavior. +- Proposes regex syntax and `RegexBuilder` API for library-defined character classes, Unicode properties, and custom character classes. - Defines how Unicode scalar-based classes are extended to grapheme clusters in the different semantic and other matching modes. diff --git a/Documentation/Evolution/UnicodeForStringProcessing.md b/Documentation/Evolution/UnicodeForStringProcessing.md new file mode 100644 index 000000000..828d8f53c --- /dev/null +++ b/Documentation/Evolution/UnicodeForStringProcessing.md @@ -0,0 +1,872 @@ +# Unicode for String Processing + +Proposal: [SE-NNNN](NNNN-filename.md) +Authors: [Nate Cook](https://github.com/natecook1000), [Alejandro Alonso](https://github.com/Azoy) +Review Manager: TBD +Implementation: [apple/swift-experimental-string-processing][repo] +Status: **Draft** + + +## Introduction + +This proposal describes `Regex`'s rich Unicode support during regex matching, along with the character classes and options that define that behavior. + +## Motivation + +Swift's `String` type provides, by default, a view of `Character`s or [extended grapheme clusters][graphemes] whose comparison honors [Unicode canonical equivalence][canoneq]. Each character in a string can be composed of one or more Unicode scalar values, while still being treated as a single unit, equivalent to other ways of formulating the equivalent character: + +```swift +let str = "Cafe\u{301}" // "Café" +str == "Café" // true +str.dropLast() // "Caf" +str.last == "é" // true (precomposed e with acute accent) +str.last == "e\u{301}" // true (e followed by composing acute accent) +``` + +This default view is fairly novel. Most languages that support Unicode strings generally operate at the Unicode scalar level, and don't provide the same affordance for operating on a string as a collection of grapheme clusters. In Python, for example, Unicode strings report their length as the number of scalar values, and don't use canonical equivalence in comparisons: + +```python +cafe = u"Cafe\u0301" +len(cafe) # 5 +cafe == u"Café" # False +``` + +Existing regex engines follow this same model of operating at the Unicode scalar level. To match canonically equivalent characters, or have equivalent behavior between equivalent strings, you must normalize your string and regex to the same canonical format. + +```python +# Matches a four-element string +re.match(u"^.{4}$", cafe) # None +# Matches a string ending with 'é' +re.match(u".+é$", cafe) # None + +cafeComp = unicodedata.normalize("NFC", cafe) +re.match(u"^.{4}$", cafeComp) # +re.match(u".+é$", cafeComp) # +``` + +With Swift's string model, this behavior would surprising and undesirable — Swift's default regex semantics must match the semantics of a `String`. + +
Other engines + +Other regex engines match character classes (such as `\w` or `.`) at the Unicode scalar value level, or even the code unit level, instead of recognizing grapheme clusters as characters. When matching the `.` character class, other languages will only match the first part of an `"e\u{301}"` grapheme cluster. Some languages, like Perl, Ruby, and Java, support an additional `\X` metacharacter, which explicitly represents a single grapheme cluster. + +| Matching `"Cafe\u{301}"` | Pattern: `^Caf.` | Remaining | Pattern: `^Caf\X` | Remaining | +|---|---|---|---|---| +| C#, Rust, Go, Python | `"Cafe"` | `"´"` | n/a | n/a | +| NSString, Java, Ruby, Perl | `"Cafe"` | `"´"` | `"Café"` | `""` | + +Other than Java's `CANON_EQ` option, the vast majority of other languages and engines are not capable of comparing with canonical equivalence. + +
+ +## Proposed solution + +In a regex's simplest form, without metacharacters or special features, matching behaves like a test for equality. A string always matches a regex that simply contains the same characters. + +```swift +let str = "Cafe\u{301}" // "Café" +str.contains(/Café/) // true +``` + +From that point, small changes continue to comport with the element counting and comparison expectations set by `String`: + +```swift +str.contains(/Caf./) // true +str.contains(/.+é/) // true +str.contains(/.+e\u{301}/) // true +str.contains(/\w+é/) // true +``` + + +For compatibility with other regex engines and the flexibility to match at both `Character` and Unicode scalar level, you can switch between matching levels for an entire regex or within select portions. This powerful capability provides the expected default behavior when working with strings, while allowing you to drop down for Unicode scalar-specific matching. + +By default, literal characters and Unicode scalar values (e.g. `\u{301}`) are coalesced into characters in the same way as a normal string, as shown above. Metacharacters, like `.` and `\w`, and custom character classes each match a single element at the current matching level. + +For example, these matches fail, because by the time the parser encounters the "`\u{301}`" Unicode scalar literal, the full `"é"` character has been matched: + +```swift +str.contains(/Caf.\u{301}) // false - `.` matches "é" character +str.contains(/Caf\w\u{301}) // false - `\w` matches "é" character +str.contains(/.+\u{301}) // false - `.+` matches each character +``` + +Alternatively, we can drop down to use Unicode scalar semantics if we want to match specific Unicode sequences. For example, these regexes matches an `"e"` followed by any modifier with the specified parameters: + +```swift +str.contains(/e[\u{300}-\u{314}]/.matchingSemantics(.unicodeScalar)) +// true - matches an "e" followed by a Unicode scalar in the range U+0300 - U+0314 +str.contains(/e\p{Nonspacing Mark}/.matchingSemantics(.unicodeScalar)) +// true - matches an "e" followed by a Unicode scalar with general category "Nonspacing Mark" +``` + +Matching in Unicode scalar mode is analogous to comparing against a string's `UnicodeScalarView` — individual Unicode scalars are matched without combining them into characters or testing for canonical equivalence. + +```swift +str.contains(/Café/.matchingSemantics(.unicodeScalar)) +// false - "e\u{301}" doesn't match with /é/ +str.contains(/Cafe\u{301}/.matchingSemantics(.unicodeScalar)) +// true - "e\u{301}" matches with /e\u{301}/ +``` + +Swift's `Regex` follows the level 2 guidelines for Unicode support in regular expressions described in [Unicode Technical Standard #18][uts18], with support for Unicode character classes, canonical equivalence, grapheme cluster matching semantics, and level 2 word boundaries enabled by default. In addition to selecting the matching semantics, `Regex` provides options for selecting different matching behaviors, such as ASCII character classes or Unicode scalar semantics, which corresponds more closely with other regex engines. + +## Detailed design + +First, we'll discuss the options that let you control a regex's behavior, and then explore the character classes that define the your pattern. + +### Options + +Options can be enabled and disabled in two different ways: as part of [regex internal syntax][internals], or applied as methods when declaring a `Regex`. For example, both of these `Regex`es are declared with case insensitivity: + +```swift +let regex1 = /(?i)banana/ +let regex2 = Regex { + "banana" +}.ignoresCase()` +``` + +Note that the `ignoresCase()` is available on any type conforming to `RegexComponent`, which means that you can always use the more readable option-setting interface in conjunction with regex literals or run-time compiled `Regex`es: + +```swift +let regex3 = /banana/.ignoresCase() +``` + +Calling an option-setting method like `ignoresCase(_:)` acts like wrapping the callee in an option-setting group `(?:...)`. That is, while it sets the behavior for the callee, it doesn’t override options that are applied to more specific regions. In this example, the middle `"na"` in `"banana"` matches case-sensitively, despite the outer call to `ignoresCase()`: + +```swift +let regex4 = Regex { + "ba" + "na".ignoresCase(false) + "na" +} +.ignoresCase() + +"banana".contains(regex4) // true +"BAnaNA".contains(regex4) // true +"BANANA".contains(regex4) // false + +// Equivalent to: +let regex5 = /(?i)ba(?-i:na)na/ +``` + +All option APIs are provided on `RegexComponent`, so they can be called on a `Regex` instance, or on any component that you would use inside a `RegexBuilder` block when the `RegexBuilder` module is imported. + +The options that `Regex` supports are shown in the table below. Options that affect _matching behavior_ are supported through both regex syntax and APIs, while options that have _structural_ or _syntactic_ effects are only supported through regex syntax. + +| **Matching Behavior** | | | +|------------------------------|----------------|---------------------------| +| Case insensitivity | `(?i)` | `ignoresCase()` | +| Single-line mode | `(?s)` | `dotMatchesNewlines()` | +| Multi-line mode | `(?m)` | `anchorsMatchNewlines()` | +| ASCII-only character classes | `(?DSWP)` | `asciiOnlyDigits()`, etc | +| Unicode word boundaries | `(?w)` | `wordBoundaryKind(_:)` | +| Semantic level | `(?Xu)` | `matchingSemantics(_:)` | +| Repetition behavior | `(?U)` | `repetitionBehavior(_:)` | +| **Structural/Syntactic** | | | +| Extended syntax | `(?x)`,`(?xx)` | n/a | +| Named captures only | `(?n)` | n/a | +| Shared capture names | `(?J)` | n/a | + +#### Case insensitivity + +Regexes perform case sensitive comparisons by default. The `i` option or the `ignoresCase(_:)` method enables case insensitive comparison. + +```swift +let str = "Café" + +str.firstMatch(of: /CAFÉ/) // nil +str.firstMatch(of: /(?i)CAFÉ/) // "Café" +str.firstMatch(of: /(?i)cAfÉ/) // "Café" +``` + +Case insensitive matching uses case folding to ensure that canonical equivalence continues to operate as expected. + +**Regex syntax:** `(?i)...` or `(?i:...)` + +**`RegexBuilder` API:** + +```swift +extension RegexComponent { + /// Returns a regular expression that ignores casing when matching. + public func ignoresCase(_ ignoresCase: Bool = true) -> Regex +} +``` + +#### Single line mode (`.` matches newlines) + +The "any" metacharacter (`.`) matches any character in a string *except* newlines by default. With the `s` option enabled, `.` matches any character including newlines. + +```swift +let str = """ + <> + """ + +str.firstMatch(of: /<<.+>>/) // nil +str.firstMatch(of: /(?s)<<.+>>/) // "This string\nuses double-angle-brackets\nto group text." +``` + +This option also affects the behavior of `CharacterClass.any`, which is designed to match the behavior of the `.` regex literal component. + +**Regex syntax:** `(?s)...` or `(?s...)` + +**`RegexBuilder` API:** + +```swift +extension RegexComponent { + /// Returns a regular expression where the start and end of input + /// anchors (`^` and `$`) also match against the start and end of a line. + public func dotMatchesNewlines(_ dotMatchesNewlines: Bool = true) -> Regex +} +``` + +#### Multiline mode + +By default, the start and end anchors (`^` and `$`) match only the beginning and end of a string. With the `m` or the option, they also match the beginning and end of each line. + +```swift +let str = """ + abc + def + ghi + """ + +str.firstMatch(of: /^abc/) // "abc" +str.firstMatch(of: /^abc$/) // nil +str.firstMatch(of: /(?m)^abc$/) // "abc" + +str.firstMatch(of: /^def/) // nil +str.firstMatch(of: /(?m)^def$/) // "def" +``` + +This option applies only to anchors used in a regex literal. The anchors defined in `RegexBuilder` are specific about matching at the start/end of the input or the line, and therefore do not correspond directly with the `^` and `$` literal anchors. + +```swift +str.firstMatch(of: Regex { Anchor.startOfInput ; "def" }) // nil +str.firstMatch(of: Regex { Anchor.startOfLine ; "def" }) // "def" +``` + +**Regex syntax:** `(?m)...` or `(?m...)` + +**`RegexBuilder` API:** + +```swift +extension RegexComponent { + /// Returns a regular expression where the start and end of input + /// anchors (`^` and `$`) also match against the start and end of a line. + public func anchorsMatchLineEndings(_ matchLineEndings: Bool = true) -> Regex +} +``` + +#### ASCII-only character classes + +With one or more of these options enabled, the default character classes match only ASCII values instead of the full Unicode range of characters. Four options are included in this group: + +* `D`: Match only ASCII members for `\d`, `\p{Digit}`, `[:digit:]`, and the `CharacterClass.digit`. +* `S`: Match only ASCII members for `\s`, `\p{Space}`, `[:space:]`. +* `W`: Match only ASCII members for `\w`, `\p{Word}`, `[:word:]`, `\b`, `CharacterClass.word`, and `Anchor.wordBoundary`. +* `P`: Match only ASCII members for all POSIX properties (including `digit`, `space`, and `word`). + +**Regex syntax:** `(?DSWP)...` or `(?DSWP...)` + +**`RegexBuilder` API:** + +```swift +extension RegexComponent { + /// Returns a regular expression that only matches ASCII characters as digits. + public func asciiOnlyDigits(_ asciiOnly: Bool = true) -> Regex + + /// Returns a regular expression that only matches ASCII characters as space + /// characters. + public func asciiOnlyWhitespace(_ asciiOnly: Bool = true) -> Regex + + /// Returns a regular expression that only matches ASCII characters as "word + /// characters". + public func asciiOnlyWordCharacters(_ asciiOnly: Bool = true) -> Regex + + /// Returns a regular expression that only matches ASCII characters when + /// matching character classes. + public func asciiOnlyCharacterClasses(_ asciiOnly: Bool = true) -> Regex +} +``` + +#### Unicode word boundaries + +By default, matching word boundaries with the `\b` and `Anchor.wordBoundary` anchors uses Unicode _default word boundaries,_ specified as [Unicode level 2 regular expression support][level2-word-boundaries]. + +Disabling the `w` option switches to _[simple word boundaries][level1-word-boundaries],_ finding word boundaries at points in the input where `\b\B` or `\B\b` match. Depending on the other matching options that are enabled, this may be more compatible with the behavior other regex engines. + +As shown in this example, the default matching behavior finds the whole first word of the string, while the match with simple word boundaries stops at the apostrophe: + +```swift +let str = "Don't look down!" + +str.firstMatch(of: /D\S+\b/) // "Don't" +str.firstMatch(of: /(?-w)D\S+\b/) // "Don" +``` + +You can see more differences between level 1 and level 2 word boundaries in the following table: + +| Example | Level 1 | Level 2 | +|---------------------|---------------------------------|-------------------------------------------| +| I can't do that. | ["I", "can", "t", "do", "that"] | ["I", "can't", "do", "that", "."] | +| 🔥😊👍 | ["🔥😊👍"] | ["🔥", "😊", "👍"] | +| 👩🏻👶🏿👨🏽🧑🏾👩🏼 | ["👩🏻👶🏿👨🏽🧑🏾👩🏼"] | ["👩🏻", "👶🏿", "👨🏽", "🧑🏾", "👩🏼"] | +| 🇨🇦🇺🇸🇲🇽 | ["🇨🇦🇺🇸🇲🇽"] | ["🇨🇦", "🇺🇸", "🇲🇽"] | +| 〱㋞ツ | ["〱", "㋞", "ツ"] | ["〱㋞ツ"] | +| hello〱㋞ツ | ["hello〱", "㋞", "ツ"] | ["hello", "〱㋞ツ"] | +| 나는 Chicago에 산다 | ["나는", "Chicago에", "산다"] | ["나", "는", "Chicago", "에", "산", "다"] | +| 眼睛love食物 | ["眼睛love食物"] | ["眼", "睛", "love", "食", "物"] | +| 아니ㅋㅋㅋ네 | ["아니ㅋㅋㅋ네"] | ["아", "니", "ㅋㅋㅋ", "네"] | +| Re:Zero | ["Re", "Zero"] | ["Re:Zero"] | +| \u{d}\u{a} | ["\u{d}", "\u{a}"] | ["\u{d}\u{a}"] | +| €1 234,56 | ["1", "234", "56"] | ["€", "1", "234,56"] | + + +**Regex syntax:** `(?-w)...` or `(?-w...)` + +**`RegexBuilder` API:** + +```swift +extension RegexComponent { + /// Returns a regular expression that uses the specified word boundary algorithm. + /// + /// A simple word boundary is a position in the input between two characters + /// that match `/\w\W/` or `/\W\w/`, or between the start or end of the input + /// and `\w` character. Word boundaries therefore depend on the option-defined + /// behavior of `\w`. + /// + /// The default word boundaries use a Unicode algorithm that handles some cases + /// better than simple word boundaries, such as words with internal + /// punctuation, changes in script, and Emoji. + public func wordBoundaryKind(_ wordBoundaryKind: RegexWordBoundaryKind) -> Regex +} + +public struct RegexWordBoundaryKind: Hashable { + /// A word boundary algorithm that implements the "simple word boundary" + /// Unicode recommendation. + /// + /// A simple word boundary is a position in the input between two characters + /// that match `/\w\W/` or `/\W\w/`, or between the start or end of the input + /// and a `\w` character. Word boundaries therefore depend on the option- + /// defined behavior of `\w`. + public static var unicodeLevel1: Self { get } + + /// A word boundary algorithm that implements the "default word boundary" + /// Unicode recommendation. + /// + /// Default word boundaries use a Unicode algorithm that handles some cases + /// better than simple word boundaries, such as words with internal + /// punctuation, changes in script, and Emoji. + public static var unicodeLevel2: Self { get } +} +``` + +#### Matching semantic level + +When matching with grapheme cluster semantics (the default), metacharacters like `.` and `\w`, custom character classes, and character class instances like `.any` match a grapheme cluster when possible, corresponding with the default string representation. In addition, matching with grapheme cluster semantics compares characters using their canonical representation, corresponding with the way comparing strings for equality works. + +When matching with Unicode scalar semantics, metacharacters and character classes always match a single Unicode scalar value, even if that scalar comprises part of a grapheme cluster. + +These semantic levels lead to different results, especially when working with strings that have decomposed characters. In the following example, `queRegex` matches any 3-character string that begins with `"q"`. + +```swift +let composed = "qué" +let decomposed = "que\u{301}" + +let queRegex = /^q..$/ + +print(composed.contains(queRegex)) +// Prints "true" +print(decomposed.contains(queRegex)) +// Prints "true" +``` + +When using Unicode scalar semantics, however, the regex only matches the composed version of the string, because each `.` matches a single Unicode scalar value. + +```swift +let queRegexScalar = queRegex.matchingSemantics(.unicodeScalar) +print(composed.contains(queRegexScalar)) +// Prints "true" +print(decomposed.contains(queRegexScalar)) +// Prints "false" +``` + +With grapheme cluster semantics, a grapheme cluster boundary is naturally enforced at the start and end of the match and every capture group. Matching with Unicode scalar semantics, on the other hand, including using the `\O` metacharacter or `.anyUnicodeScalar` character class, can yield string indices that aren't aligned to character boundaries. Take care when using indices that aren't aligned with grapheme cluster boundaries, as they may have to be rounded to a boundary if used in a `String` instance. + +```swift +let family = "👨‍👨‍👧‍👦 is a family" + +// Grapheme-cluster mode: Yields a character +let firstCharacter = /^./ +let characterMatch = family.firstMatch(of: firstCharacter)!.output +print(characterMatch) +// Prints "👨‍👨‍👧‍👦" + +// Unicode-scalar mode: Yields only part of a character +let firstUnicodeScalar = /^./.matchingSemantics(.unicodeScalar) +let unicodeScalarMatch = family.firstMatch(of: firstUnicodeScalar)!.output +print(unicodeScalarMatch) +// Prints "👨" + +// The end of `unicodeScalarMatch` is not aligned on a character boundary +print(unicodeScalarMatch.endIndex == family.index(after: family.startIndex)) +// Prints "false" +``` + +When a regex proceeds with grapheme cluster semantics from a position that _isn't_ grapheme cluster aligned, it attempts to match the partial grapheme cluster that starts at that point. In the first call to `contains(_:)` below, `\O` matches a single Unicode scalar value, as shown above, and then the engine tries to match `\s` against the remainder of the family emoji character. Because that character is not whitespace, the match fails. The second call uses `\X`, which matches the entire emoji character, and then successfully matches the following space. + +```swift +// \O matches a single Unicode scalar, whatever the current semantics +family.contains(/^\O\s/)) // false + +// \X matches a single character, whatever the current semantics +family.contains(/^\X\s/) // true +``` + +**Regex syntax:** `(?X)...` or `(?X...)` for grapheme cluster semantics, `(?u)...` or `(?u...)` for Unicode scalar semantics. + +**`RegexBuilder` API:** + +```swift +extension RegexComponent { + /// Returns a regular expression that matches with the specified semantic + /// level. + public func matchingSemantics(_ semanticLevel: RegexSemanticLevel) -> Regex +} + +public struct RegexSemanticLevel: Hashable { + /// Match at the default semantic level of a string, where each matched + /// element is a `Character`. + public static var graphemeCluster: RegexSemanticLevel + + /// Match at the semantic level of a string's `UnicodeScalarView`, where each + /// matched element is a `UnicodeScalar` value. + public static var unicodeScalar: RegexSemanticLevel +} +``` + +#### Default repetition behavior + +Regex quantifiers (`+`, `*`, and `?`) match eagerly by default when they repeat, such that they match the longest possible substring. Appending `?` to a quantifier makes it reluctant, instead, so that it matches the shortest possible substring. + +```swift +let str = "A value." + +// By default, the '+' quantifier is eager, and consumes as much as possible. +str.firstMatch(of: /<.+>/) // "A value." + +// Adding '?' makes the '+' quantifier reluctant, so that it consumes as little as possible. +str.firstMatch(of: /<.+?>/) // "" +``` + +The `U` option toggles the "eagerness" of quantifiers, so that quantifiers are reluctant by default, and only become eager when `?` is added to the quantifier. + +```swift +// '(?U)' toggles the eagerness of quantifiers: +str.firstMatch(of: /(?U)<.+>/) // "" +str.firstMatch(of: /(?U)<.+?>/) // "A value." +``` + +**Regex syntax:** `(?U)...` or `(?U...)` + +**`RegexBuilder` API:** + +The `repetitionBehavior(_:)` method lets you set the default behavior for all quantifiers that don't explicitly provide their own behavior. For example, you can make all quantifiers behave possessively, eliminating any quantification-caused backtracking. + +```swift +extension RegexComponent { + /// Returns a regular expression where quantifiers are reluctant by default + /// instead of eager. + public func repetitionBehavior(_ behavior: RegexRepetitionBehavior) -> Regex +} + +public struct RegexRepetitionBehavior { + /// Match as much of the input string as possible, backtracking when + /// necessary. + public static var eager: RegexRepetitionBehavior { get } + + /// Match as little of the input string as possible, expanding the matched + /// region as necessary to complete a match. + public static var reluctant: RegexRepetitionBehavior { get } + + /// Match as much of the input string as possible, performing no backtracking. + public static var possessive: RegexRepetitionBehavior { get } +} +``` + +In order for this option to have the same effect on regexes built with `RegexBuilder` as with regex syntax, the `RegexBuilder` quantifier APIs are amended to have an `nil`-defaulted optional `behavior` parameter. For example: + +```swift +extension OneOrMore { + public init( + _ behavior: RegexRepetitionBehavior? = nil, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0), Component.Output == (W, C0) +} +``` + +When you pass `nil`, the quantifier uses the default behavior as set by this option (either eager or reluctant). If an explicit behavior is passed, that behavior is used regardless of the default. + + +--- + +### Character Classes + +We propose the following definitions for regex character classes, along with a `CharacterClass` type as part of the `RegexBuilder` module, to encapsulate and simplify character class usage within builder-style regexes. + +The two regexes defined in this example will match the same inputs, looking for one or more word characters followed by up to three digits, optionally separated by a space: + +```swift +let regex1 = /\w+\s?\d{,3}/ +let regex2 = Regex { + OneOrMore(.word) + Optionally(.whitespace) + Repeat(.digit, ...3) +} +``` + +You can build custom character classes by combining regex-defined classes with individual characters or ranges, or by performing common set operations such as subtracting or negating a character class. + + +#### “Any” + +The simplest character class, representing **any character**, is written as `.` or `CharacterClass.any` and is also referred to as the "dot" metacharacter. This class always matches a single `Character` or Unicode scalar value, depending on the matching semantic level. This class excludes newlines, unless "single line mode" is enabled (see section above). + +In the following example, using grapheme cluster semantics, a dot matches a grapheme cluster, so the decomposed é is treated as a single value: + +```swift +"Cafe\u{301}".contains(/C.../) +// true +``` + +For this example, using Unicode scalar semantics, a dot matches only a single Unicode scalar value, so the combining marks don't get grouped with the commas before them: + +```swift +let data = "\u{300},\u{301},\u{302},\u{303},..." +for match in data.matches(of: /(.),/.matchingSemantics(.unicodeScalar)) { + print(match.1) +} +// Prints: +// ̀ +// ́ +// ̂ +// ... +``` + +`Regex` also provides ways to select a specific level of "any" matching, without needing to change semantic levels. + +- The **any grapheme cluster** character class is written as `\X` or `CharacterClass.anyGraphemeCluster`, and matches from the current location up to the next grapheme cluster boundary. This includes matching newlines, regardless of any option settings. This metacharacter is equivalent to the regex syntax `(?s-u:.)`. +- The **any Unicode scalar** character class is written as `\O` or `CharacterClass.anyUnicodeScalar`, and matches exactly one Unicode scalar value at the current location. This includes matching newlines, regardless of any option settings, but only the first scalar in an `\r\n` cluster. This metacharacter is equivalent to the regex syntax `(?su:.)`. + +#### Digits + +The **decimal digit** character class is matched by `\d` or `CharacterClass.digit`. Both regexes in this example match one or more decimal digits followed by a colon: + +```swift +let regex1 = /\d+:/ +let regex2 = Regex { + OneOrMore(.digit) + ":" +} +``` + +_Unicode scalar semantics:_ Matches a Unicode scalar that has a `numericType` property equal to `.decimal`. This includes the digits from the ASCII range, from the _Halfwidth and Fullwidth Forms_ Unicode block, as well as digits in some scripts, like `DEVANAGARI DIGIT NINE` (U+096F). This corresponds to the general category `Decimal_Number`. + +_Grapheme cluster semantics:_ Matches a character made up of a single Unicode scalar that fits the decimal digit criteria above. + +_ASCII mode_: Matches a Unicode scalar in the range `0` to `9`. + + +To invert the decimal digit character class, use `\D` or `CharacterClass.digit.inverted`. + + +The **hexadecimal digit** character class is matched by `CharacterClass.hexDigit`. + +_Unicode scalar semantics:_ Matches a decimal digit, as described above, or an uppercase or small `A` through `F` from the _Halfwidth and Fullwidth Forms_ Unicode block. Note that this is a broader class than described by the `UnicodeScalar.properties.isHexDigit` property, as that property only include ASCII and fullwidth decimal digits. + +_Grapheme cluster semantics:_ Matches a character made up of a single Unicode scalar that fits the hex digit criteria above. + +_ASCII mode_: Matches a Unicode scalar in the range `0` to `9`, `a` to `f`, or `A` to `F`. + +To invert the hexadecimal digit character class, use `CharacterClass.hexDigit.inverted`. + +*
Rationale* + +Unicode's recommended definition for `\d` is its [numeric type][numerictype] of "Decimal" in contrast to "Digit". It is specifically restricted to sets of ascending contiguously-encoded scalars in a decimal radix positional numeral system. Thus, it excludes "digits" such as superscript numerals from its [definition][derivednumeric] and is a proper subset of `Character.isWholeNumber`. + +We interpret Unicode's definition of the set of scalars, especially its requirement that scalars be encoded in ascending chains, to imply that this class is restricted to scalars which meaningfully encode base-10 digits. Thus, we choose to make the grapheme cluster interpretation *restrictive*. + +
+ + +#### "Word" characters + +The **word** character class is matched by `\w` or `CharacterClass.word`. This character class and its name are essentially terms of art within regexes, and represents part of a notional "word". Note that, by default, this is distinct from the algorithm for identifying word boundaries. + +_Unicode scalar semantics:_ Matches a Unicode scalar that has one of the Unicode properties `Alphabetic`, `Digit`, or `Join_Control`, or is in the general category `Mark` or `Connector_Punctuation`. + +_Grapheme cluster semantics:_ Matches a character that begins with a Unicode scalar value that fits the criteria above. + +_ASCII mode_: Matches the numbers `0` through `9`, lowercase and uppercase `A` through `Z`, and the underscore (`_`). + +To invert the word character class, use `\W` or `CharacterClass.word.inverted`. + +*
Rationale* + +Word characters include more than letters, and we went with Unicode's recommended scalar semantics. Following the Unicode recommendation that nonspacing marks remain with their base characters, we extend to grapheme clusters similarly to `Character.isLetter`. That is, combining scalars do not change the word-character-ness of the grapheme cluster. + +
+ + +#### Whitespace and newlines + +The **whitespace** character class is matched by `\s` and `CharacterClass.whitespace`. + +_Unicode scalar semantics:_ Matches a Unicode scalar that has the Unicode properties `Whitespace`, including a space, a horizontal tab (U+0009), `LINE FEED (LF)` (U+000A), `LINE TABULATION` (U+000B), `FORM FEED (FF)` (U+000C), `CARRIAGE RETURN (CR)` (U+000D), and `NEWLINE (NEL)` (U+0085). Note that under Unicode scalar semantics, `\s` only matches the first scalar in a `CR`+`LF` pair. + +_Grapheme cluster semantics:_ Matches a character that begins with a `Whitespace` Unicode scalar value. This includes matching a `CR`+`LF` pair. + +_ASCII mode_: Matches characters that both ASCII and fit the criteria given above. The current matching semantics dictate whether a `CR`+`LF` pair is matched in ASCII mode. + +The **horizontal whitespace** character class is matched by `\h` and `CharacterClass.horizontalWhitespace`. + +_Unicode scalar semantics:_ Matches a Unicode scalar that has the Unicode general category `Zs`/`Space_Separator` as well as a horizontal tab (U+0009). + +_Grapheme cluster semantics:_ Matches a character that begins with a Unicode scalar value that fits the criteria above. + +_ASCII mode_: Matches either a space (`" "`) or a horizontal tab. + +The **vertical whitespace** character class is matched by `\v` and `CharacterClass.verticalWhitespace`. Additionally, `\R` and `CharacterClass.newline` provide a way to include the `CR`+`LF` pair, even when matching with Unicode scalar semantics. + +_Unicode scalar semantics:_ Matches a Unicode scalar that has the Unicode general category `Zl`/`Line_Separator` as well as any of the following control characters: `LINE FEED (LF)` (U+000A), `LINE TABULATION` (U+000B), `FORM FEED (FF)` (U+000C), `CARRIAGE RETURN (CR)` (U+000D), and `NEWLINE (NEL)` (U+0085). Only when specified as `\R` or `CharacterClass.newline` does this match the whole `CR`+`LF` pair. + +_Grapheme cluster semantics:_ Matches a character that begins with a Unicode scalar value that fits the criteria above. + +_ASCII mode_: Matches any of the four ASCII control characters listed above. The current matching semantics dictate whether a `CR`+`LF` pair is matched in ASCII mode. + +To invert these character classes, use `\S`, `\H`, and `\V`, respectively, or the `inverted` property on a `CharacterClass` instance. + +
Rationale + +Note that "whitespace" is a term-of-art and is not correlated with visibility, which is a completely separate concept. + +We use Unicode's recommended scalar semantics for horizontal and vertical whitespace, extended to grapheme clusters as in the existing `Character.isWhitespace` property. + +
+ + +#### Unicode properties + +Character classes that match **Unicode properties** are written as `\p{PROPERTY}` or `\p{PROPERTY=VALUE}`, as described in the [Run-time Regex Construction proposal][internals-properties]. + +While most Unicode properties are only defined at the scalar level, some are defined to match an extended grapheme cluster. For example, `\p{RGI_Emoji_Flag_Sequence}` will match any flag emoji character, which are composed of two Unicode scalar values. Such property classes will match multiple scalars, even when matching with Unicode scalar semantics. + +Unicode property matching is extended to `Character`s with a goal of consistency with other regex character classes. For `\p{Decimal}` and `\p{Hex_Digit}`, only single-scalar `Character`s can match, for the reasons described in that section, above. For all other Unicode property classes, matching `Character`s can comprise multiple scalars, as long as the first scalar matches the property. + +To invert a Unicode property character class, use `\P{...}`. + + +#### POSIX character classes: `[:NAME:]` + +**POSIX character classes** represent concepts that we'd like to define at all semantic levels. We propose the following definitions, some of which have been described above. When matching with grapheme cluster semantics, Unicode properties are extended to `Character`s as descrived in the rationale above, and as shown in the table below. That is, for POSIX class `[:word:]`, any `Character` that starts with a matching scalar is a match, while for `[:digit:]`, a matching `Character` must only comprise a single Unicode scalar value. + +| POSIX class | Unicode property class | Character behavior | ASCII mode value | +|--------------|-----------------------------------|----------------------|-------------------------------| +| `[:lower:]` | `\p{Lowercase}` | starts-with | `[a-z]` | +| `[:upper:]` | `\p{Uppercase}` | starts-with | `[A-Z]` | +| `[:alpha:]` | `\p{Alphabetic}` | starts-with | `[A-Za-z]` | +| `[:alnum:]` | `[\p{Alphabetic}\p{Decimal}]` | starts-with | `[A-Za-z0-9]` | +| `[:word:]` | See \* below | starts-with | `[[:alnum:]_]` | +| `[:digit:]` | `\p{DecimalNumber}` | single-scalar | `[0-9]` | +| `[:xdigit:]` | `\p{Hex_Digit}` | single-scalar | `[0-9A-Fa-f]` | +| `[:punct:]` | `\p{Punctuation}` | starts-with | `[-!"#%&'()*,./:;?@[\\\]{}]` | +| `[:blank:]` | `[\p{Space_Separator}\u{09}]` | starts-with | `[ \t]` | +| `[:space:]` | `\p{Whitespace}` | starts-with | `[ \t\n\r\f\v]` | +| `[:cntrl:]` | `\p{Control}` | starts-with | `[\x00-\x1f\x7f]` | +| `[:graph:]` | See \*\* below | starts-with | `[^ [:cntrl:]]` | +| `[:print:]` | `[[:graph:][:blank:]--[:cntrl:]]` | starts-with | `[[:graph:] ]` | + +\* The Unicode scalar property definition for `[:word:]` is `[\p{Alphanumeric}\p{Mark}\p{Join_Control}\p{Connector_Punctuation}]`. +\*\* The Unicode scalar property definition for `[:cntrl:]` is `[^\p{Space}\p{Control}\p{Surrogate}\p{Unassigned}]`. + +#### Custom classes + +Custom classes function as the set union of their individual components, whether those parts are individual characters, individual Unicode scalar values, ranges, Unicode property classes or POSIX classes, or other custom classes. + +- Individual characters and scalars will be tested using the same behavior as if they were listed in an alternation. That is, a custom character class like `[abc]` is equivalent to `(a|b|c)` under the same options and modes. +- When in grapheme cluster semantic mode, ranges of characters will test for membership using NFD form (or NFKD when performing caseless matching). This differs from how a `ClosedRange` would operate its `contains` method, since that depends on `String`'s `Comparable` conformance, but the decomposed comparison better aligns with the canonical equivalence matching used elsewhere in `Regex`. +- A custom character class will match a maximum of one `Character` or `UnicodeScalar`, depending on the matching semantic level. This means that a custom character class with extended grapheme cluster members may not match anything while using scalar semantics. + +Inside regexes, custom classes are enclosed in square brackets `[...]`, and can be nested or combined using set operators like `&&`. For more detail, see the [Run-time Regex Construction proposal][internals-charclass]. + +With `RegexBuilder`'s `CharacterClass` type, you can use built-in character classes with ranges and groups of characters. For example, to parse a valid octodecimal number, you could define a custom character class that combines `.digit` with a range of characters. + +```swift +let octoDecimalRegex: Regex<(Substring, Int?)> = Regex { + let charClass = CharacterClass(.digit, "a"..."h").ignoresCase() + Capture { + OneOrMore(charClass) + } transform: { Int($0, radix: 18) } +} +``` + +The full `CharacterClass` API is as follows: + +```swift +public struct CharacterClass: RegexComponent { + public var regex: Regex { get } + + public var inverted: CharacterClass { get } +} + +extension RegexComponent where Self == CharacterClass { + public static var any: CharacterClass { get } + + public static var anyGraphemeCluster: CharacterClass { get } + + public static var anyUnicodeScalar: CharacterClass { get } + + public static var digit: CharacterClass { get } + + public static var hexDigit: CharacterClass { get } + + public static var word: CharacterClass { get } + + public static var whitespace: CharacterClass { get } + + public static var horizontalWhitespace: CharacterClass { get } + + public static var newlineSequence: CharacterClass { get } + + public static var verticalWhitespace: CharacterClass { get } +} + +extension RegexComponent where Self == CharacterClass { + /// Returns a character class that matches any character in the given string + /// or sequence. + public static func anyOf(_ s: S) -> CharacterClass + where S.Element == Character + + /// Returns a character class that matches any unicode scalar in the given + /// sequence. + public static func anyOf(_ s: S) -> CharacterClass + where S.Element == UnicodeScalar +} + +// Unicode properties +extension CharacterClass { + /// Returns a character class that matches elements in the given Unicode + /// general category. + public static func generalCategory(_ category: Unicode.GeneralCategory) -> CharacterClass +} + +// Set algebra methods +extension CharacterClass { + /// Creates a character class that combines the given classes in a union. + public init(_ first: CharacterClass, _ rest: CharacterClass...) + + /// Returns a character class from the union of this class and the given class. + public func union(_ other: CharacterClass) -> CharacterClass + + /// Returns a character class from the intersection of this class and the given class. + public func intersection(_ other: CharacterClass) -> CharacterClass + + /// Returns a character class by subtracting the given class from this class. + public func subtracting(_ other: CharacterClass) -> CharacterClass + + /// Returns a character class matching elements in one or the other, but not both, + /// of this class and the given class. + public func symmetricDifference(_ other: CharacterClass) -> CharacterClass +} + +/// Range syntax for characters in `CharacterClass`es. +public func ...(lhs: Character, rhs: Character) -> CharacterClass + +/// Range syntax for unicode scalars in `CharacterClass`es. +@_disfavoredOverload +public func ...(lhs: UnicodeScalar, rhs: UnicodeScalar) -> CharacterClass +``` + +## Source compatibility + +Everything in this proposal is additive, and has no compatibility effect on existing source code. + +## Effect on ABI stability + +Everything in this proposal is additive, and has no effect on existing stable ABI. + +## Effect on API resilience + +N/A + +## Future directions + +### Expanded options and modifiers + +The initial version of `Regex` includes only the options described above. Filling out the remainder of options described in the [Run-time Regex Construction proposal][literals] could be completed as future work, as well as additional improvements, such as adding an option that makes a regex match only at the start of a string. + +### Extensions to Character and Unicode Scalar APIs + +An earlier version of this pitch described adding standard library APIs to `Character` and `UnicodeScalar` for each of the supported character classes, as well as convenient static members for control characters. In addition, regex literals support Unicode property features that don’t currently exist in the standard library, such as a scalar’s script or extended category, or creating a scalar by its Unicode name instead of its scalar value. These kinds of additions are + +### Byte semantic mode + +A future `Regex` version could support a byte-level semantic mode in addition to grapheme cluster and Unicode scalar semantics. Byte-level semantics would allow matching individual bytes, potentially providing the capability of parsing string and non-string data together. + +### More general `CharacterSet` replacement + +Foundation's `CharacterSet` type is in some ways similar to the `CharacterClass` type defined in this proposal. `CharacterSet` is primarily a set type that is defined over Unicode scalars, and can therefore sometimes be awkward to use in conjunction with Swift `String`s. The proposed `CharacterClass` type is a `RegexBuilder`-specific type, and as such isn't intended to be a full general purpose replacement. Future work could involve expanding upon the `CharacterClass` API or introducing a different type to fill that role. + +## Alternatives considered + +### Operate on String.UnicodeScalarView instead of using semantic modes + +Instead of providing APIs to select whether `Regex` matching is `Character`-based vs. `UnicodeScalar`-based, we could instead provide methods to match against the different views of a string. This different approach has multiple drawbacks: + +* As the scalar level used when matching changes the behavior of individual components of a `Regex`, it’s more appropriate to specify the semantic level at the declaration site than the call site. +* With the proposed options model, you can define a Regex that includes different semantic levels for different portions of the match, which would be impossible with a call site-based approach. + +### Binary word boundary option method + +A prior version of this proposal used a binary method for setting the word boundary algorithm, called `usingSimpleWordBoundaries()`. A method taking a `RegexWordBoundaryKind` instance is included in the proposal instead, to leave room for implementing other word boundary algorithms in the future. + + +[repo]: https://github.com/apple/swift-experimental-string-processing/ +[option-scoping]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md#matching-options +[internals]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md +[internals-properties]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md#character-properties +[internals-charclass]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md#custom-character-classes +[level1-word-boundaries]:https://unicode.org/reports/tr18/#Simple_Word_Boundaries +[level2-word-boundaries]:https://unicode.org/reports/tr18/#RL2.3 + +[overview]: https://forums.swift.org/t/declarative-string-processing-overview/52459 +[charprops]: https://github.com/apple/swift-evolution/blob/master/proposals/0221-character-properties.md +[charpropsrationale]: https://github.com/apple/swift-evolution/blob/master/proposals/0221-character-properties.md#detailed-semantics-and-rationale +[canoneq]: https://www.unicode.org/reports/tr15/#Canon_Compat_Equivalence +[graphemes]: https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries +[meaningless]: https://forums.swift.org/t/declarative-string-processing-overview/52459/121 +[scalarprops]: https://github.com/apple/swift-evolution/blob/master/proposals/0211-unicode-scalar-properties.md +[ucd]: https://www.unicode.org/reports/tr44/tr44-28.html +[numerictype]: https://www.unicode.org/reports/tr44/#Numeric_Type +[derivednumeric]: https://www.unicode.org/Public/UCD/latest/ucd/extracted/DerivedNumericType.txt + + +[uts18]: https://unicode.org/reports/tr18/ +[proplist]: https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt +[pcre]: https://www.pcre.org/current/doc/html/pcre2pattern.html +[perl]: https://perldoc.perl.org/perlre +[raku]: https://docs.raku.org/language/regexes +[rust]: https://docs.rs/regex/1.5.4/regex/ +[python]: https://docs.python.org/3/library/re.html +[ruby]: https://ruby-doc.org/core-2.4.0/Regexp.html +[csharp]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference +[icu]: https://unicode-org.github.io/icu/userguide/strings/regexp.html +[posix]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html +[oniguruma]: https://www.cuminas.jp/sdk/regularExpression.html +[go]: https://pkg.go.dev/regexp/syntax@go1.17.2 +[cplusplus]: https://www.cplusplus.com/reference/regex/ECMAScript/ +[ecmascript]: https://262.ecma-international.org/12.0/#sec-pattern-semantics +[re2]: https://github.com/google/re2/wiki/Syntax +[java]: https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index cc5afda39..1483996d1 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -445,6 +445,14 @@ class RegexDSLTests: XCTestCase { Repeat(2...) { "e" } Repeat(0...) { "f" } } + + let octoDecimalRegex: Regex<(Substring, Int?)> = Regex { + let charClass = CharacterClass(.digit, "a"..."h")//.ignoringCase() + Capture { + OneOrMore(charClass) + } transform: { Int($0, radix: 18) } + } + XCTAssertEqual("ab12".firstMatch(of: octoDecimalRegex)!.output.1, 61904) } func testAssertions() throws { From 81bc5d0979dcda578c87683b476996a59633e866 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Fri, 22 Apr 2022 10:50:17 -0600 Subject: [PATCH 092/133] Updates for algorithms proposal (#319) * Rename custom match prefix protocol and add doc comments * Update algo proposal prose --- Documentation/Evolution/ProposalOverview.md | 2 +- Documentation/Evolution/RegexTypeOverview.md | 10 ++--- .../Evolution/StringProcessingAlgorithms.md | 43 ++++++++++--------- .../Regex/CustomComponents.swift | 39 +++++++++++++++++ .../Regex/DSLConsumers.swift | 29 ------------- Tests/RegexBuilderTests/CustomTests.swift | 12 +++--- Tests/RegexBuilderTests/RegexDSLTests.swift | 4 +- 7 files changed, 75 insertions(+), 64 deletions(-) create mode 100644 Sources/_StringProcessing/Regex/CustomComponents.swift delete mode 100644 Sources/_StringProcessing/Regex/DSLConsumers.swift diff --git a/Documentation/Evolution/ProposalOverview.md b/Documentation/Evolution/ProposalOverview.md index f3c3ac6d1..898e0db20 100644 --- a/Documentation/Evolution/ProposalOverview.md +++ b/Documentation/Evolution/ProposalOverview.md @@ -39,7 +39,7 @@ Covers the "interior" syntax, extended syntaxes, run-time construction of a rege Proposes a slew of Regex-powered algorithms. -Introduces `CustomMatchingRegexComponent`, which is a monadic-parser style interface for external parsers to be used as components of a regex. +Introduces `CustomPrefixMatchRegexComponent`, which is a monadic-parser style interface for external parsers to be used as components of a regex. ## Unicode for String Processing diff --git a/Documentation/Evolution/RegexTypeOverview.md b/Documentation/Evolution/RegexTypeOverview.md index 6eed648f0..68dd6ccc7 100644 --- a/Documentation/Evolution/RegexTypeOverview.md +++ b/Documentation/Evolution/RegexTypeOverview.md @@ -231,7 +231,7 @@ The result builder allows for inline failable value construction, which particip Swift regexes describe an unambiguous algorithm, where choice is ordered and effects can be reliably observed. For example, a `print()` statement inside the `TryCapture`'s transform function will run whenever the overall algorithm naturally dictates an attempt should be made. Optimizations can only elide such calls if they can prove it is behavior-preserving (e.g. "pure"). -`CustomMatchingRegexComponent`, discussed in [String Processing Algorithms][pitches], allows industrial-strength parsers to be used a regex components. This allows us to drop the overly-permissive pre-parsing step: +`CustomPrefixMatchRegexComponent`, discussed in [String Processing Algorithms][pitches], allows industrial-strength parsers to be used a regex components. This allows us to drop the overly-permissive pre-parsing step: ```swift func processEntry(_ line: String) -> Transaction? { @@ -431,7 +431,7 @@ Regular expressions have a deservedly mixed reputation, owing to their historica * "Regular expressions are bad because you should use a real parser" - In other systems, you're either in or you're out, leading to a gravitational pull to stay in when... you should get out - - Our remedy is interoperability with real parsers via `CustomMatchingRegexComponent` + - Our remedy is interoperability with real parsers via `CustomPrefixMatchRegexComponent` - Literals with refactoring actions provide an incremental off-ramp from regex syntax to result builders and real parsers * "Regular expressions are bad because ugly unmaintainable syntax" - We propose literals with source tools support, allowing for better syntax highlighting and analysis @@ -516,7 +516,7 @@ Regex are compiled into an intermediary representation and fairly simple analysi ### Future work: parser combinators -What we propose here is an incremental step towards better parsing support in Swift using parser-combinator style libraries. The underlying execution engine supports recursive function calls and mechanisms for library extensibility. `CustomMatchingRegexComponent`'s protocol requirement is effectively a [monadic parser](https://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf), meaning `Regex` provides a regex-flavored combinator-like system. +What we propose here is an incremental step towards better parsing support in Swift using parser-combinator style libraries. The underlying execution engine supports recursive function calls and mechanisms for library extensibility. `CustomPrefixMatchRegexComponent`'s protocol requirement is effectively a [monadic parser](https://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf), meaning `Regex` provides a regex-flavored combinator-like system. An issues with traditional parser combinator libraries are the compilation barriers between call-site and definition, resulting in excessive and overly-cautious backtracking traffic. These can be eliminated through better [compilation techniques](https://core.ac.uk/download/pdf/148008325.pdf). As mentioned above, Swift's support for custom static compilation is still under development. @@ -565,9 +565,9 @@ Regexes are often used for tokenization and tokens can be represented with Swift ### Future work: baked-in localized processing -- `CustomMatchingRegexComponent` gives an entry point for localized processors +- `CustomPrefixMatchRegexComponent` gives an entry point for localized processors - Future work includes (sub?)protocols to communicate localization intent --> -[pitches]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/ProposalOverview.md \ No newline at end of file +[pitches]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/ProposalOverview.md diff --git a/Documentation/Evolution/StringProcessingAlgorithms.md b/Documentation/Evolution/StringProcessingAlgorithms.md index 74416ae63..edefbd19b 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -8,9 +8,9 @@ We propose: 1. New regex-powered algorithms over strings, bringing the standard library up to parity with scripting languages 2. Generic `Collection` equivalents of these algorithms in terms of subsequences -3. `protocol CustomMatchingRegexComponent`, which allows 3rd party libraries to provide their industrial-strength parsers as intermixable components of regexes +3. `protocol CustomPrefixMatchRegexComponent`, which allows 3rd party libraries to provide their industrial-strength parsers as intermixable components of regexes -This proposal is part of a larger [regex-powered string processing initiative](https://forums.swift.org/t/declarative-string-processing-overview/52459). Throughout the document, we will reference the still-in-progress [`RegexProtocol`, `Regex`](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/StronglyTypedCaptures.md), and result builder DSL, but these are in flux and not formally part of this proposal. Further discussion of regex specifics is out of scope of this proposal and better discussed in another thread (see [Pitch and Proposal Status](https://github.com/apple/swift-experimental-string-processing/issues/107) for links to relevant threads). +This proposal is part of a larger [regex-powered string processing initiative](https://github.com/apple/swift-evolution/blob/main/proposals/0350-regex-type-overview.md), the status of each proposal is tracked [here](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/ProposalOverview.md). Further discussion of regex specifics is out of scope of this proposal and better discussed in their relevant reviews. ## Motivation @@ -91,18 +91,18 @@ Note: Only a subset of Python's string processing API are included in this table ### Complex string processing -Even with the API additions, more complex string processing quickly becomes unwieldy. Up-coming support for authoring regexes in Swift help alleviate this somewhat, but string processing in the modern world involves dealing with localization, standards-conforming validation, and other concerns for which a dedicated parser is required. +Even with the API additions, more complex string processing quickly becomes unwieldy. String processing in the modern world involves dealing with localization, standards-conforming validation, and other concerns for which a dedicated parser is required. Consider parsing the date field `"Date: Wed, 16 Feb 2022 23:53:19 GMT"` in an HTTP header as a `Date` type. The naive approach is to search for a substring that looks like a date string (`16 Feb 2022`), and attempt to post-process it as a `Date` with a date parser: ```swift let regex = Regex { - capture { - oneOrMore(.digit) + Capture { + OneOrMore(.digit) " " - oneOrMore(.word) + OneOrMore(.word) " " - oneOrMore(.digit) + OneOrMore(.digit) } } @@ -128,21 +128,21 @@ DEBIT 03/24/2020 IRX tax payment ($52,249.98) Parsing a currency string such as `$3,020.85` with regex is also tricky, as it can contain localized and currency symbols in addition to accounting conventions. This is why Foundation provides industrial-strength parsers for localized strings. -## Proposed solution +## Proposed solution ### Complex string processing -We propose a `CustomMatchingRegexComponent` protocol which allows types from outside the standard library participate in regex builders and `RegexComponent` algorithms. This allows types, such as `Date.ParseStrategy` and `FloatingPointFormatStyle.Currency`, to be used directly within a regex: +We propose a `CustomPrefixMatchRegexComponent` protocol which allows types from outside the standard library participate in regex builders and `RegexComponent` algorithms. This allows types, such as `Date.ParseStrategy` and `FloatingPointFormatStyle.Currency`, to be used directly within a regex: ```swift let dateRegex = Regex { - capture(dateParser) + Capture(dateParser) } let date: Date = header.firstMatch(of: dateRegex).map(\.result.1) let currencyRegex = Regex { - capture(.localizedCurrency(code: "USD").sign(strategy: .accounting)) + Capture(.localizedCurrency(code: "USD").sign(strategy: .accounting)) } let amount: [Decimal] = statement.matches(of: currencyRegex).map(\.result.1) @@ -167,24 +167,25 @@ We also propose the following regex-powered algorithms as well as their generic |`matches(of:)`| Returns a collection containing all matches of the specified `RegexComponent` | -## Detailed design +## Detailed design -### `CustomMatchingRegexComponent` +### `CustomPrefixMatchRegexComponent` -`CustomMatchingRegexComponent` inherits from `RegexComponent` and satisfies its sole requirement; Conformers can be used with all of the string algorithms generic over `RegexComponent`. +`CustomPrefixMatchRegexComponent` inherits from `RegexComponent` and satisfies its sole requirement. Conformers can be used with all of the string algorithms generic over `RegexComponent`. ```swift -/// A protocol for custom match functionality. -public protocol CustomMatchingRegexComponent : RegexComponent { - /// Match the input string within the specified bounds, beginning at the given index, and return - /// the end position (upper bound) of the match and the matched instance. +/// A protocol allowing custom types to function as regex components by +/// providing the raw functionality backing `prefixMatch`. +public protocol CustomPrefixMatchRegexComponent: RegexComponent { + /// Process the input string within the specified bounds, beginning at the given index, and return + /// the end position (upper bound) of the match and the produced output. /// - Parameters: /// - input: The string in which the match is performed. /// - index: An index of `input` at which to begin matching. /// - bounds: The bounds in `input` in which the match is performed. /// - Returns: The upper bound where the match terminates and a matched instance, or `nil` if /// there isn't a match. - func match( + func consuming( _ input: String, startingAt index: String.Index, in bounds: Range @@ -198,8 +199,8 @@ public protocol CustomMatchingRegexComponent : RegexComponent { We use Foundation `FloatingPointFormatStyle.Currency` as an example for protocol conformance. It would implement the `match` function with `Match` being a `Decimal`. It could also add a static function `.localizedCurrency(code:)` as a member of `RegexComponent`, so it can be referred as `.localizedCurrency(code:)` in the `Regex` result builder: ```swift -extension FloatingPointFormatStyle.Currency : CustomMatchingRegexComponent { - public func match( +extension FloatingPointFormatStyle.Currency : CustomPrefixMatchRegexComponent { + public func consuming( _ input: String, startingAt index: String.Index, in bounds: Range diff --git a/Sources/_StringProcessing/Regex/CustomComponents.swift b/Sources/_StringProcessing/Regex/CustomComponents.swift new file mode 100644 index 000000000..e8111555c --- /dev/null +++ b/Sources/_StringProcessing/Regex/CustomComponents.swift @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +@available(SwiftStdlib 5.7, *) +/// A protocol allowing custom types to function as regex components by +/// providing the raw functionality backing `prefixMatch`. +public protocol CustomPrefixMatchRegexComponent: RegexComponent { + /// Process the input string within the specified bounds, beginning at the given index, and return + /// the end position (upper bound) of the match and the produced output. + /// - Parameters: + /// - input: The string in which the match is performed. + /// - index: An index of `input` at which to begin matching. + /// - bounds: The bounds in `input` in which the match is performed. + /// - Returns: The upper bound where the match terminates and a matched instance, or `nil` if + /// there isn't a match. + func consuming( + _ input: String, + startingAt index: String.Index, + in bounds: Range + ) throws -> (upperBound: String.Index, output: RegexOutput)? +} + +@available(SwiftStdlib 5.7, *) +extension CustomPrefixMatchRegexComponent { + public var regex: Regex { + let node: DSLTree.Node = .matcher(RegexOutput.self, { input, index, bounds in + try consuming(input, startingAt: index, in: bounds) + }) + return Regex(node: node) + } +} diff --git a/Sources/_StringProcessing/Regex/DSLConsumers.swift b/Sources/_StringProcessing/Regex/DSLConsumers.swift deleted file mode 100644 index eb8ace8d3..000000000 --- a/Sources/_StringProcessing/Regex/DSLConsumers.swift +++ /dev/null @@ -1,29 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// -//===----------------------------------------------------------------------===// - -@available(SwiftStdlib 5.7, *) -public protocol CustomMatchingRegexComponent: RegexComponent { - func match( - _ input: String, - startingAt index: String.Index, - in bounds: Range - ) throws -> (upperBound: String.Index, output: RegexOutput)? -} - -@available(SwiftStdlib 5.7, *) -extension CustomMatchingRegexComponent { - public var regex: Regex { - let node: DSLTree.Node = .matcher(RegexOutput.self, { input, index, bounds in - try match(input, startingAt: index, in: bounds) - }) - return Regex(node: node) - } -} diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index d17c3a142..269f9ebaa 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -14,13 +14,13 @@ import _StringProcessing @testable import RegexBuilder // A nibbler processes a single character from a string -private protocol Nibbler: CustomMatchingRegexComponent { +private protocol Nibbler: CustomPrefixMatchRegexComponent { func nibble(_: Character) -> RegexOutput? } extension Nibbler { // Default implementation, just feed the character in - func match( + func consuming( _ input: String, startingAt index: String.Index, in bounds: Range @@ -49,10 +49,10 @@ private struct Asciibbler: Nibbler { } } -private struct IntParser: CustomMatchingRegexComponent { +private struct IntParser: CustomPrefixMatchRegexComponent { struct ParseError: Error, Hashable {} typealias RegexOutput = Int - func match(_ input: String, + func consuming(_ input: String, startingAt index: String.Index, in bounds: Range ) throws -> (upperBound: String.Index, output: Int)? { @@ -71,7 +71,7 @@ private struct IntParser: CustomMatchingRegexComponent { } } -private struct CurrencyParser: CustomMatchingRegexComponent { +private struct CurrencyParser: CustomPrefixMatchRegexComponent { enum Currency: String, Hashable { case usd = "USD" case ntd = "NTD" @@ -84,7 +84,7 @@ private struct CurrencyParser: CustomMatchingRegexComponent { } typealias RegexOutput = Currency - func match(_ input: String, + func consuming(_ input: String, startingAt index: String.Index, in bounds: Range ) throws -> (upperBound: String.Index, output: Currency)? { diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 1483996d1..cd1c94657 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -863,9 +863,9 @@ class RegexDSLTests: XCTestCase { var patch: Int var dev: String? } - struct SemanticVersionParser: CustomMatchingRegexComponent { + struct SemanticVersionParser: CustomPrefixMatchRegexComponent { typealias RegexOutput = SemanticVersion - func match( + func consuming( _ input: String, startingAt index: String.Index, in bounds: Range From 89b80bfe180ea3940ae9a35bb5765f69f448ec4e Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Mon, 11 Apr 2022 09:59:04 -0700 Subject: [PATCH 093/133] Preparation for location aware diagnostics in the compiler. Moving `libswiftLexRegexLiteral()` and `libswiftParseRegexLiteral()` to the compiler repository because these functions are basically just briding the compiler to the actual lexing/parsing function. * Make some Lexing error APIs public. * Make LocatedErrorProtocol public and expose the `location` property * Shift the location of `LocatedError` in `parseWithDelimiters` so the client can get the valid string indices of the passed-in literal string. --- .../Regex/Parse/DelimiterLexing.swift | 18 ++++++++++++------ .../Regex/Parse/LexicalAnalysis.swift | 2 +- Sources/_RegexParser/Regex/Parse/Mocking.swift | 3 +++ Sources/_RegexParser/Regex/Parse/Parse.swift | 12 +++++++++++- .../Regex/Parse/SourceLocation.swift | 11 +++++++++-- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/Sources/_RegexParser/Regex/Parse/DelimiterLexing.swift b/Sources/_RegexParser/Regex/Parse/DelimiterLexing.swift index bee782043..dd142f016 100644 --- a/Sources/_RegexParser/Regex/Parse/DelimiterLexing.swift +++ b/Sources/_RegexParser/Regex/Parse/DelimiterLexing.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -struct Delimiter: Hashable { +public struct Delimiter: Hashable { let kind: Kind let poundCount: Int @@ -74,8 +74,8 @@ extension Delimiter { } } -struct DelimiterLexError: Error, CustomStringConvertible { - enum Kind: Hashable { +public struct DelimiterLexError: Error, CustomStringConvertible { + public enum Kind: Hashable { case unterminated case invalidUTF8 // TODO: better range reporting case unknownDelimiter @@ -83,17 +83,17 @@ struct DelimiterLexError: Error, CustomStringConvertible { case multilineClosingNotOnNewline } - var kind: Kind + public var kind: Kind /// The pointer at which to resume lexing. - var resumePtr: UnsafeRawPointer + public var resumePtr: UnsafeRawPointer init(_ kind: Kind, resumeAt resumePtr: UnsafeRawPointer) { self.kind = kind self.resumePtr = resumePtr } - var description: String { + public var description: String { switch kind { case .unterminated: return "unterminated regex literal" case .invalidUTF8: return "invalid UTF-8 found in source file" @@ -462,3 +462,9 @@ func lexRegex( var lexer = DelimiterLexer(start: start, end: end, delimiters: delimiters) return try lexer.lex() } + +public func lexRegex( + start: UnsafeRawPointer, end: UnsafeRawPointer +) throws -> (contents: String, Delimiter, end: UnsafeRawPointer) { + return try lexRegex(start: start, end: end, delimiters: Delimiter.enabledDelimiters) +} diff --git a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift index 6a61ccdf7..9633b607e 100644 --- a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift +++ b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift @@ -24,7 +24,7 @@ API convention: extension Error { func addingLocation(_ loc: Range) -> Error { // If we're already a LocatedError, don't change the location. - if self is _LocatedErrorProtocol { + if self is LocatedErrorProtocol { return self } return Source.LocatedError(self, loc) diff --git a/Sources/_RegexParser/Regex/Parse/Mocking.swift b/Sources/_RegexParser/Regex/Parse/Mocking.swift index dd02e0fc7..56294e2d3 100644 --- a/Sources/_RegexParser/Regex/Parse/Mocking.swift +++ b/Sources/_RegexParser/Regex/Parse/Mocking.swift @@ -9,6 +9,7 @@ // //===----------------------------------------------------------------------===// +@available(*, deprecated, message: "moving to SwiftCompilerModules") private func copyCString(_ str: String) -> UnsafePointer { let count = str.utf8.count + 1 return str.withCString { @@ -36,6 +37,7 @@ private func copyCString(_ str: String) -> UnsafePointer { /// - Returns: A bool indicating whether lexing was completely erroneous, and /// cannot be recovered from, or false if there either was no error, /// or there was a recoverable error. +@available(*, deprecated, message: "moving to SwiftCompilerModules") func libswiftLexRegexLiteral( _ curPtrPtr: UnsafeMutablePointer?>?, _ bufferEndPtr: UnsafePointer?, @@ -93,6 +95,7 @@ public let currentRegexLiteralFormatVersion: CUnsignedInt = 1 /// capture structure. /// - captureStructureSize: The size of the capture structure buffer. Must be /// greater than or equal to `strlen(inputPtr)`. +@available(*, deprecated, message: "moving to SwiftCompilerModules") func libswiftParseRegexLiteral( _ inputPtr: UnsafePointer?, _ errOut: UnsafeMutablePointer?>?, diff --git a/Sources/_RegexParser/Regex/Parse/Parse.swift b/Sources/_RegexParser/Regex/Parse/Parse.swift index 975012546..a2790924a 100644 --- a/Sources/_RegexParser/Regex/Parse/Parse.swift +++ b/Sources/_RegexParser/Regex/Parse/Parse.swift @@ -583,5 +583,15 @@ public func parseWithDelimiters( _ regex: S ) throws -> AST where S.SubSequence == Substring { let (contents, delim) = droppingRegexDelimiters(String(regex)) - return try parse(contents, defaultSyntaxOptions(delim, contents: contents)) + do { + return try parse(contents, defaultSyntaxOptions(delim, contents: contents)) + } catch let error as LocatedErrorProtocol { + // Convert the range in 'contents' to the range in 'regex'. + let delimCount = delim.opening.count + let offsets = contents.offsets(of: error.location.range) + let startIndex = regex.index(atOffset: delimCount + offsets.lowerBound) + let endIndex = regex.index(atOffset: delimCount + offsets.upperBound) + + throw error._typeErasedError.addingLocation(startIndex..: Error, _LocatedErrorProtocol { + public struct LocatedError: Error, LocatedErrorProtocol { public let error: E public let location: SourceLocation @@ -118,4 +121,8 @@ extension Source.LocatedError: CustomStringConvertible { // we present the message to the compiler. "\(error)" } + + public var _typeErasedError: Error { + return error + } } From 1f99047dfc1e6ae9c567d7f5449e247fcb01b0d6 Mon Sep 17 00:00:00 2001 From: Tina Liu <49205802+itingliu@users.noreply.github.com> Date: Fri, 22 Apr 2022 15:18:36 -0700 Subject: [PATCH 094/133] Rename CustomPrefixMatchRegexComponent to CustomConsumingRegexComponent (#326) --- Documentation/Evolution/ProposalOverview.md | 2 +- Documentation/Evolution/RegexTypeOverview.md | 8 ++++---- .../Evolution/StringProcessingAlgorithms.md | 12 ++++++------ .../_StringProcessing/Regex/CustomComponents.swift | 4 ++-- Tests/RegexBuilderTests/CustomTests.swift | 6 +++--- Tests/RegexBuilderTests/RegexDSLTests.swift | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Documentation/Evolution/ProposalOverview.md b/Documentation/Evolution/ProposalOverview.md index 898e0db20..7656526a6 100644 --- a/Documentation/Evolution/ProposalOverview.md +++ b/Documentation/Evolution/ProposalOverview.md @@ -39,7 +39,7 @@ Covers the "interior" syntax, extended syntaxes, run-time construction of a rege Proposes a slew of Regex-powered algorithms. -Introduces `CustomPrefixMatchRegexComponent`, which is a monadic-parser style interface for external parsers to be used as components of a regex. +Introduces `CustomConsumingRegexComponent`, which is a monadic-parser style interface for external parsers to be used as components of a regex. ## Unicode for String Processing diff --git a/Documentation/Evolution/RegexTypeOverview.md b/Documentation/Evolution/RegexTypeOverview.md index 68dd6ccc7..94230d724 100644 --- a/Documentation/Evolution/RegexTypeOverview.md +++ b/Documentation/Evolution/RegexTypeOverview.md @@ -231,7 +231,7 @@ The result builder allows for inline failable value construction, which particip Swift regexes describe an unambiguous algorithm, where choice is ordered and effects can be reliably observed. For example, a `print()` statement inside the `TryCapture`'s transform function will run whenever the overall algorithm naturally dictates an attempt should be made. Optimizations can only elide such calls if they can prove it is behavior-preserving (e.g. "pure"). -`CustomPrefixMatchRegexComponent`, discussed in [String Processing Algorithms][pitches], allows industrial-strength parsers to be used a regex components. This allows us to drop the overly-permissive pre-parsing step: +`CustomConsumingRegexComponent`, discussed in [String Processing Algorithms][pitches], allows industrial-strength parsers to be used a regex components. This allows us to drop the overly-permissive pre-parsing step: ```swift func processEntry(_ line: String) -> Transaction? { @@ -431,7 +431,7 @@ Regular expressions have a deservedly mixed reputation, owing to their historica * "Regular expressions are bad because you should use a real parser" - In other systems, you're either in or you're out, leading to a gravitational pull to stay in when... you should get out - - Our remedy is interoperability with real parsers via `CustomPrefixMatchRegexComponent` + - Our remedy is interoperability with real parsers via `CustomConsumingRegexComponent` - Literals with refactoring actions provide an incremental off-ramp from regex syntax to result builders and real parsers * "Regular expressions are bad because ugly unmaintainable syntax" - We propose literals with source tools support, allowing for better syntax highlighting and analysis @@ -516,7 +516,7 @@ Regex are compiled into an intermediary representation and fairly simple analysi ### Future work: parser combinators -What we propose here is an incremental step towards better parsing support in Swift using parser-combinator style libraries. The underlying execution engine supports recursive function calls and mechanisms for library extensibility. `CustomPrefixMatchRegexComponent`'s protocol requirement is effectively a [monadic parser](https://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf), meaning `Regex` provides a regex-flavored combinator-like system. +What we propose here is an incremental step towards better parsing support in Swift using parser-combinator style libraries. The underlying execution engine supports recursive function calls and mechanisms for library extensibility. `CustomConsumingRegexComponent`'s protocol requirement is effectively a [monadic parser](https://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf), meaning `Regex` provides a regex-flavored combinator-like system. An issues with traditional parser combinator libraries are the compilation barriers between call-site and definition, resulting in excessive and overly-cautious backtracking traffic. These can be eliminated through better [compilation techniques](https://core.ac.uk/download/pdf/148008325.pdf). As mentioned above, Swift's support for custom static compilation is still under development. @@ -565,7 +565,7 @@ Regexes are often used for tokenization and tokens can be represented with Swift ### Future work: baked-in localized processing -- `CustomPrefixMatchRegexComponent` gives an entry point for localized processors +- `CustomConsumingRegexComponent` gives an entry point for localized processors - Future work includes (sub?)protocols to communicate localization intent --> diff --git a/Documentation/Evolution/StringProcessingAlgorithms.md b/Documentation/Evolution/StringProcessingAlgorithms.md index edefbd19b..263c00d3b 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -8,7 +8,7 @@ We propose: 1. New regex-powered algorithms over strings, bringing the standard library up to parity with scripting languages 2. Generic `Collection` equivalents of these algorithms in terms of subsequences -3. `protocol CustomPrefixMatchRegexComponent`, which allows 3rd party libraries to provide their industrial-strength parsers as intermixable components of regexes +3. `protocol CustomConsumingRegexComponent`, which allows 3rd party libraries to provide their industrial-strength parsers as intermixable components of regexes This proposal is part of a larger [regex-powered string processing initiative](https://github.com/apple/swift-evolution/blob/main/proposals/0350-regex-type-overview.md), the status of each proposal is tracked [here](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/ProposalOverview.md). Further discussion of regex specifics is out of scope of this proposal and better discussed in their relevant reviews. @@ -132,7 +132,7 @@ Parsing a currency string such as `$3,020.85` with regex is also tricky, as it c ### Complex string processing -We propose a `CustomPrefixMatchRegexComponent` protocol which allows types from outside the standard library participate in regex builders and `RegexComponent` algorithms. This allows types, such as `Date.ParseStrategy` and `FloatingPointFormatStyle.Currency`, to be used directly within a regex: +We propose a `CustomConsumingRegexComponent` protocol which allows types from outside the standard library participate in regex builders and `RegexComponent` algorithms. This allows types, such as `Date.ParseStrategy` and `FloatingPointFormatStyle.Currency`, to be used directly within a regex: ```swift let dateRegex = Regex { @@ -169,14 +169,14 @@ We also propose the following regex-powered algorithms as well as their generic ## Detailed design -### `CustomPrefixMatchRegexComponent` +### `CustomConsumingRegexComponent` -`CustomPrefixMatchRegexComponent` inherits from `RegexComponent` and satisfies its sole requirement. Conformers can be used with all of the string algorithms generic over `RegexComponent`. +`CustomConsumingRegexComponent` inherits from `RegexComponent` and satisfies its sole requirement. Conformers can be used with all of the string algorithms generic over `RegexComponent`. ```swift /// A protocol allowing custom types to function as regex components by /// providing the raw functionality backing `prefixMatch`. -public protocol CustomPrefixMatchRegexComponent: RegexComponent { +public protocol CustomConsumingRegexComponent: RegexComponent { /// Process the input string within the specified bounds, beginning at the given index, and return /// the end position (upper bound) of the match and the produced output. /// - Parameters: @@ -199,7 +199,7 @@ public protocol CustomPrefixMatchRegexComponent: RegexComponent { We use Foundation `FloatingPointFormatStyle.Currency` as an example for protocol conformance. It would implement the `match` function with `Match` being a `Decimal`. It could also add a static function `.localizedCurrency(code:)` as a member of `RegexComponent`, so it can be referred as `.localizedCurrency(code:)` in the `Regex` result builder: ```swift -extension FloatingPointFormatStyle.Currency : CustomPrefixMatchRegexComponent { +extension FloatingPointFormatStyle.Currency : CustomConsumingRegexComponent { public func consuming( _ input: String, startingAt index: String.Index, diff --git a/Sources/_StringProcessing/Regex/CustomComponents.swift b/Sources/_StringProcessing/Regex/CustomComponents.swift index e8111555c..d675c3ae7 100644 --- a/Sources/_StringProcessing/Regex/CustomComponents.swift +++ b/Sources/_StringProcessing/Regex/CustomComponents.swift @@ -12,7 +12,7 @@ @available(SwiftStdlib 5.7, *) /// A protocol allowing custom types to function as regex components by /// providing the raw functionality backing `prefixMatch`. -public protocol CustomPrefixMatchRegexComponent: RegexComponent { +public protocol CustomConsumingRegexComponent: RegexComponent { /// Process the input string within the specified bounds, beginning at the given index, and return /// the end position (upper bound) of the match and the produced output. /// - Parameters: @@ -29,7 +29,7 @@ public protocol CustomPrefixMatchRegexComponent: RegexComponent { } @available(SwiftStdlib 5.7, *) -extension CustomPrefixMatchRegexComponent { +extension CustomConsumingRegexComponent { public var regex: Regex { let node: DSLTree.Node = .matcher(RegexOutput.self, { input, index, bounds in try consuming(input, startingAt: index, in: bounds) diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index 269f9ebaa..bc71f2363 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -14,7 +14,7 @@ import _StringProcessing @testable import RegexBuilder // A nibbler processes a single character from a string -private protocol Nibbler: CustomPrefixMatchRegexComponent { +private protocol Nibbler: CustomConsumingRegexComponent { func nibble(_: Character) -> RegexOutput? } @@ -49,7 +49,7 @@ private struct Asciibbler: Nibbler { } } -private struct IntParser: CustomPrefixMatchRegexComponent { +private struct IntParser: CustomConsumingRegexComponent { struct ParseError: Error, Hashable {} typealias RegexOutput = Int func consuming(_ input: String, @@ -71,7 +71,7 @@ private struct IntParser: CustomPrefixMatchRegexComponent { } } -private struct CurrencyParser: CustomPrefixMatchRegexComponent { +private struct CurrencyParser: CustomConsumingRegexComponent { enum Currency: String, Hashable { case usd = "USD" case ntd = "NTD" diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index cd1c94657..7c06fd6c3 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -863,7 +863,7 @@ class RegexDSLTests: XCTestCase { var patch: Int var dev: String? } - struct SemanticVersionParser: CustomPrefixMatchRegexComponent { + struct SemanticVersionParser: CustomConsumingRegexComponent { typealias RegexOutput = SemanticVersion func consuming( _ input: String, From 563d6c2220b26c1ba368352c2a98bb02e7e83670 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Fri, 22 Apr 2022 17:43:48 -0700 Subject: [PATCH 095/133] Remove String.Index evils --- .../_StringProcessing/Unicode/NecessaryEvils.swift | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Sources/_StringProcessing/Unicode/NecessaryEvils.swift b/Sources/_StringProcessing/Unicode/NecessaryEvils.swift index a9ae24429..672a731bd 100644 --- a/Sources/_StringProcessing/Unicode/NecessaryEvils.swift +++ b/Sources/_StringProcessing/Unicode/NecessaryEvils.swift @@ -88,14 +88,3 @@ extension UTF16 { (UInt32(lead & 0x03ff) &<< 10 | UInt32(trail & 0x03ff))) } } - -extension String.Index { - internal var _encodedOffset: Int { - // The encoded offset is found in the top 48 bits. - Int(unsafeBitCast(self, to: UInt64.self) >> 16) - } - - internal init(_encodedOffset offset: Int) { - self = unsafeBitCast(offset << 16, to: Self.self) - } -} From 571e259acb96c915a2a3e55deb22b58beda345f8 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 22 Apr 2022 22:13:01 -0500 Subject: [PATCH 096/133] More updates for algorithms proposal (#324) * Update Sequence/Collection polarity * Add a note about new generics features * Update split methods, catch some inconsistencies * Adopt opaque parameter types where possible today Also includes some generic naming updates and typo fixes. * Update documentation parameters * split(by:) -> split(separator:) --- .../Evolution/StringProcessingAlgorithms.md | 148 +++++++++++------- 1 file changed, 93 insertions(+), 55 deletions(-) diff --git a/Documentation/Evolution/StringProcessingAlgorithms.md b/Documentation/Evolution/StringProcessingAlgorithms.md index 263c00d3b..6c591c268 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -14,7 +14,7 @@ This proposal is part of a larger [regex-powered string processing initiative](h ## Motivation -A number of common string processing APIs are missing from the Swift standard library. While most of the desired functionalities can be accomplished through a series of API calls, every gap adds a burden to developers doing frequent or complex string processing. For example, here's one approach to find the number of occurrences a substring ("banana") within a string: +A number of common string processing APIs are missing from the Swift standard library. While most of the desired functionalities can be accomplished through a series of API calls, every gap adds a burden to developers doing frequent or complex string processing. For example, here's one approach to find the number of occurrences of a substring ("banana") within a string: ```swift let str = "A banana a day keeps the doctor away. I love bananas; banana are my favorite fruit." @@ -216,10 +216,10 @@ Matching and extracting a localized currency amount, such as `"$3,020.85"`, can ```swift let regex = Regex { - capture(.localizedCurreny(code: "USD")) + Capture(.localizedCurrency(code: "USD")) } ``` - +
@@ -234,7 +234,7 @@ extension Collection where Element: Equatable { /// - Parameter other: A sequence to search for within this collection. /// - Returns: `true` if the collection contains the specified sequence, /// otherwise `false`. - public func contains(_ other: S) -> Bool + public func contains(_ other: C) -> Bool where S.Element == Element } @@ -244,7 +244,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: A regex to search for within this collection. /// - Returns: `true` if the regex was found in the collection, otherwise /// `false`. - public func contains(_ regex: R) -> Bool + public func contains(_ regex: some RegexComponent) -> Bool } ``` @@ -257,7 +257,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: A regex to compare to this sequence. /// - Returns: `true` if the initial elements of the sequence matches the /// beginning of `regex`; otherwise, `false`. - public func starts(with regex: R) -> Bool + public func starts(with regex: some RegexComponent) -> Bool } ``` @@ -281,7 +281,7 @@ extension Collection where SubSequence == Self { /// - Parameter predicate: A closure that takes an element of the sequence /// as its argument and returns a Boolean value indicating whether the /// element should be removed from the collection. - public mutating func trimPrefix(while predicate: (Element) throws -> Bool) + public mutating func trimPrefix(while predicate: (Element) throws -> Bool) rethrows } extension RangeReplaceableCollection { @@ -290,7 +290,7 @@ extension RangeReplaceableCollection { /// - Parameter predicate: A closure that takes an element of the sequence /// as its argument and returns a Boolean value indicating whether the /// element should be removed from the collection. - public mutating func trimPrefix(while predicate: (Element) throws -> Bool) + public mutating func trimPrefix(while predicate: (Element) throws -> Bool) rethrows } extension Collection where Element: Equatable { @@ -299,21 +299,21 @@ extension Collection where Element: Equatable { /// - Parameter prefix: The collection to remove from this collection. /// - Returns: A collection containing the elements that does not match /// `prefix` from the start. - public func trimmingPrefix(_ prefix: Prefix) -> SubSequence + public func trimmingPrefix(_ prefix: Prefix) -> SubSequence where Prefix.Element == Element } extension Collection where SubSequence == Self, Element: Equatable { /// Removes the initial elements that matches `prefix` from the start. /// - Parameter prefix: The collection to remove from this collection. - public mutating func trimPrefix(_ prefix: Prefix) + public mutating func trimPrefix(_ prefix: Prefix) where Prefix.Element == Element } extension RangeReplaceableCollection where Element: Equatable { /// Removes the initial elements that matches `prefix` from the start. /// - Parameter prefix: The collection to remove from this collection. - public mutating func trimPrefix(_ prefix: Prefix) + public mutating func trimPrefix(_ prefix: Prefix) where Prefix.Element == Element } @@ -323,7 +323,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: The regex to remove from this collection. /// - Returns: A new subsequence containing the elements of the collection /// that does not match `prefix` from the start. - public func trimmingPrefix(_ regex: R) -> SubSequence + public func trimmingPrefix(_ regex: some RegexComponent) -> SubSequence } extension RangeReplaceableCollection @@ -331,7 +331,7 @@ extension RangeReplaceableCollection { /// Removes the initial elements that matches the given regex. /// - Parameter regex: The regex to remove from this collection. - public mutating func trimPrefix(_ regex: R) + public mutating func trimPrefix(_ regex: some RegexComponent) } ``` @@ -344,8 +344,8 @@ extension Collection where Element: Equatable { /// - Parameter sequence: The sequence to search for. /// - Returns: A range in the collection of the first occurrence of `sequence`. /// Returns nil if `sequence` is not found. - public func firstRange(of sequence: S) -> Range? - where S.Element == Element + public func firstRange(of other: C) -> Range? + where C.Element == Element } extension BidirectionalCollection where Element: Comparable { @@ -354,8 +354,8 @@ extension BidirectionalCollection where Element: Comparable { /// - Parameter other: The sequence to search for. /// - Returns: A range in the collection of the first occurrence of `sequence`. /// Returns `nil` if `sequence` is not found. - public func firstRange(of other: S) -> Range? - where S.Element == Element + public func firstRange(of other: C) -> Range? + where C.Element == Element } extension BidirectionalCollection where SubSequence == Substring { @@ -364,7 +364,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: The regex to search for. /// - Returns: A range in the collection of the first occurrence of `regex`. /// Returns `nil` if `regex` is not found. - public func firstRange(of regex: R) -> Range? + public func firstRange(of regex: some RegexComponent) -> Range? } ``` @@ -377,8 +377,8 @@ extension Collection where Element: Equatable { /// - Parameter other: The sequence to search for. /// - Returns: A collection of ranges of all occurrences of `other`. Returns /// an empty collection if `other` is not found. - public func ranges(of other: S) -> some Collection> - where S.Element == Element + public func ranges(of other: C) -> some Collection> + where C.Element == Element } extension BidirectionalCollection where SubSequence == Substring { @@ -387,7 +387,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: The regex to search for. /// - Returns: A collection or ranges in the receiver of all occurrences of /// `regex`. Returns an empty collection if `regex` is not found. - public func ranges(of regex: R) -> some Collection> + public func ranges(of regex: some RegexComponent) -> some Collection> } ``` @@ -399,17 +399,17 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: The regex to search for. /// - Returns: The first match of `regex` in the collection, or `nil` if /// there isn't a match. - public func firstMatch(of regex: R) -> RegexMatch? + public func firstMatch(of regex: R) -> Regex.Match? /// Match a regex in its entirety. - /// - Parameter r: The regex to match against. + /// - Parameter regex: The regex to match against. /// - Returns: The match if there is one, or `nil` if none. - public func wholeMatch(of r: R) -> Regex.Match? + public func wholeMatch(of regex: R) -> Regex.Match? /// Match part of the regex, starting at the beginning. - /// - Parameter r: The regex to match against. + /// - Parameter regex: The regex to match against. /// - Returns: The match if there is one, or `nil` if none. - public func prefixMatch(of r: R) -> Regex.Match? + public func prefixMatch(of regex: R) -> Regex.Match? } ``` @@ -420,7 +420,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// Returns a collection containing all matches of the specified regex. /// - Parameter regex: The regex to search for. /// - Returns: A collection of matches of `regex`. - public func matches(of regex: R) -> some Collection> + public func matches(of regex: R) -> some Collection.Match> } ``` @@ -438,12 +438,12 @@ extension RangeReplaceableCollection where Element: Equatable { /// to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of `other` in /// `subrange` of the collection are replaced by `replacement`. - public func replacing( - _ other: S, + public func replacing( + _ other: C, with replacement: Replacement, subrange: Range, maxReplacements: Int = .max - ) -> Self where S.Element == Element, Replacement.Element == Element + ) -> Self where C.Element == Element, Replacement.Element == Element /// Returns a new collection in which all occurrences of a target sequence /// are replaced by another collection. @@ -454,11 +454,11 @@ extension RangeReplaceableCollection where Element: Equatable { /// to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of `other` in /// `subrange` of the collection are replaced by `replacement`. - public func replacing( - _ other: S, + public func replacing( + _ other: C, with replacement: Replacement, maxReplacements: Int = .max - ) -> Self where S.Element == Element, Replacement.Element == Element + ) -> Self where C.Element == Element, Replacement.Element == Element /// Replaces all occurrences of a target sequence with a given collection /// - Parameters: @@ -466,11 +466,11 @@ extension RangeReplaceableCollection where Element: Equatable { /// - replacement: The new elements to add to the collection. /// - maxReplacements: A number specifying how many occurrences of `other` /// to replace. Default is `Int.max`. - public mutating func replace( - _ other: S, + public mutating func replace( + _ other: C, with replacement: Replacement, maxReplacements: Int = .max - ) where S.Element == Element, Replacement.Element == Element + ) where C.Element == Element, Replacement.Element == Element } extension RangeReplaceableCollection where SubSequence == Substring { @@ -484,8 +484,8 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// sequence matching `regex` to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` in `subrange` are replaced by `replacement`. - public func replacing( - _ r: R, + public func replacing( + _ r: some RegexComponent, with replacement: Replacement, subrange: Range, maxReplacements: Int = .max @@ -500,8 +500,8 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// sequence matching `regex` to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. - public func replacing( - _ r: R, + public func replacing( + _ r: some RegexComponent, with replacement: Replacement, maxReplacements: Int = .max ) -> Self where Replacement.Element == Element @@ -513,8 +513,8 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - replacement: The new elements to add to the collection. /// - maxReplacements: A number specifying how many occurrences of the /// sequence matching `regex` to replace. Default is `Int.max`. - public mutating func replace( - _ r: R, + public mutating func replace( + _ r: some RegexComponent, with replacement: Replacement, maxReplacements: Int = .max ) where Replacement.Element == Element @@ -534,7 +534,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { _ regex: R, subrange: Range, maxReplacements: Int = .max, - with replacement: (RegexMatch) throws -> Replacement + with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element /// Returns a new collection in which all occurrences of a sequence matching @@ -550,7 +550,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { public func replacing( _ regex: R, maxReplacements: Int = .max, - with replacement: (RegexMatch) throws -> Replacement + with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element /// Replaces all occurrences of the sequence matching the given regex with @@ -564,7 +564,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { public mutating func replace( _ regex: R, maxReplacements: Int = .max, - with replacement: (RegexMatch) throws -> Replacement + with replacement: (Regex.Match) throws -> Replacement ) rethrows where Replacement.Element == Element } ``` @@ -574,27 +574,65 @@ extension RangeReplaceableCollection where SubSequence == Substring { ```swift extension Collection where Element: Equatable { /// Returns the longest possible subsequences of the collection, in order, - /// around elements equal to the given separator. - /// - Parameter separator: The element to be split upon. + /// around elements equal to the given separator collection. + /// + /// - Parameters: + /// - separator: A collection of elements to be split upon. + /// - maxSplits: The maximum number of times to split the collection, + /// or one less than the number of subsequences to return. + /// - omittingEmptySubsequences: If `false`, an empty subsequence is + /// returned in the result for each consecutive pair of separator + /// sequences in the collection and for each instance of separator + /// sequences at the start or end of the collection. If `true`, only + /// nonempty subsequences are returned. /// - Returns: A collection of subsequences, split from this collection's - /// elements. - public func split(by separator: S) -> some Collection - where S.Element == Element + /// elements. + public func split( + separator: C, + maxSplits: Int = Int.max, + omittingEmptySubsequences: Bool = true + ) -> some Collection where C.Element == Element } extension BidirectionalCollection where SubSequence == Substring { /// Returns the longest possible subsequences of the collection, in order, - /// around elements equal to the given separator. - /// - Parameter separator: A regex describing elements to be split upon. + /// around subsequence that match the given separator regex. + /// + /// - Parameters: + /// - separator: A regex to be split upon. + /// - maxSplits: The maximum number of times to split the collection, + /// or one less than the number of subsequences to return. + /// - omittingEmptySubsequences: If `false`, an empty subsequence is + /// returned in the result for each consecutive pair of matches + /// and for each match at the start or end of the collection. If + /// `true`, only nonempty subsequences are returned. /// - Returns: A collection of substrings, split from this collection's - /// elements. - public func split(by separator: R) -> some Collection + /// elements. + public func split( + separator: some RegexComponent, + maxSplits: Int = Int.max, + omittingEmptySubsequences: Bool = true + ) -> some Collection } ``` +**Note:** We plan to adopt the new generics features enabled by [SE-0346][] for these proposed methods when the standard library adopts primary associated types, [pending a forthcoming proposal][stdlib-pitch]. For example, the first method in the _Replacement_ section above would instead be: +```swift +extension RangeReplaceableCollection where Element: Equatable { + /// Returns a new collection in which all occurrences of a target sequence + /// are replaced by another collection. + public func replacing( + _ other: some Collection, + with replacement: some Collection, + subrange: Range, + maxReplacements: Int = .max + ) -> Self +} +``` - +[SE-0346]: https://github.com/apple/swift-evolution/blob/main/proposals/0346-light-weight-same-type-syntax.md +[stdlib-pitch]: https://forums.swift.org/t/pitch-primary-associated-types-in-the-standard-library/56426 ## Alternatives considered From 2df0f2457fc4daac875b9ef2c3f823a64b5ce097 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Sat, 23 Apr 2022 12:13:12 -0600 Subject: [PATCH 097/133] Add ~= overloads (#335) --- Sources/_StringProcessing/Regex/Match.swift | 12 ++++++++++++ Tests/RegexTests/AlgorithmsTests.swift | 15 +++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index e38af43f8..39ff7ece9 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -185,3 +185,15 @@ extension Regex { self.init(node: .quotedLiteral(string)) } } + +@available(SwiftStdlib 5.7, *) +public func ~=(regex: Regex, input: String) -> Bool { + guard let _ = try? regex.wholeMatch(in: input) else { return false } + return true +} + +@available(SwiftStdlib 5.7, *) +public func ~=(regex: Regex, input: Substring) -> Bool { + guard let _ = try? regex.wholeMatch(in: input) else { return false } + return true +} diff --git a/Tests/RegexTests/AlgorithmsTests.swift b/Tests/RegexTests/AlgorithmsTests.swift index a788ad13c..d19d6c43d 100644 --- a/Tests/RegexTests/AlgorithmsTests.swift +++ b/Tests/RegexTests/AlgorithmsTests.swift @@ -172,4 +172,19 @@ class RegexConsumerTests: XCTestCase { s2.matches(of: regex).map(\.0), ["aa"]) } + + func testSwitches() { + switch "abcde" { + case try! Regex("a.*f"): + XCTFail() + case try! Regex("abc"): + XCTFail() + + case try! Regex("a.*e"): + break // success + + default: + XCTFail() + } + } } From dfa4ea1cefb35fd0269dbc534cf7cca50c42aadc Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Sat, 23 Apr 2022 15:50:49 -0500 Subject: [PATCH 098/133] Fix a missed type name change --- Sources/VariadicsGenerator/VariadicsGenerator.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index c5c7dec97..85c298c20 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -517,7 +517,7 @@ struct VariadicsGenerator: ParsableCommand { \(params.disfavored)\ public init<\(params.genericParams), R: RangeExpression>( _ expression: R, - _ behavior: QuantificationBehavior? = nil, + _ behavior: RegexRepetitionBehavior? = nil, @\(concatBuilderName) _ component: () -> Component ) \(params.repeatingWhereClause) { self.init(node: .repeating(expression.relative(to: 0.. Date: Sat, 23 Apr 2022 15:51:17 -0500 Subject: [PATCH 099/133] Add a default arity and an flag for silencing logs --- .../VariadicsGenerator.swift | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index 85c298c20..f57cd8caa 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -101,8 +101,17 @@ let defaultAvailableAttr = "@available(SwiftStdlib 5.7, *)" @main struct VariadicsGenerator: ParsableCommand { @Option(help: "The maximum arity of declarations to generate.") - var maxArity: Int + var maxArity: Int = 10 + + @Flag(help: "Suppress status messages while generating.") + var silent: Bool = false + func log(_ message: String, terminator: String = "\n") { + if !silent { + print(message, terminator: terminator, to: &standardError) + } + } + func run() throws { precondition(maxArity > 1) precondition(maxArity < Counter.bitWidth) @@ -126,14 +135,12 @@ struct VariadicsGenerator: ParsableCommand { """) - print("Generating concatenation overloads...", to: &standardError) + log("Generating concatenation overloads...") for (leftArity, rightArity) in Permutations(totalArity: maxArity) { guard rightArity != 0 else { continue } - print( - " Left arity: \(leftArity) Right arity: \(rightArity)", - to: &standardError) + log(" Left arity: \(leftArity) Right arity: \(rightArity)") emitConcatenation(leftArity: leftArity, rightArity: rightArity) } @@ -143,42 +150,40 @@ struct VariadicsGenerator: ParsableCommand { output("\n\n") - print("Generating quantifiers...", to: &standardError) + log("Generating quantifiers...") for arity in 0...maxArity { - print(" Arity \(arity): ", terminator: "", to: &standardError) + log(" Arity \(arity): ", terminator: "") for kind in QuantifierKind.allCases { - print("\(kind.rawValue) ", terminator: "", to: &standardError) + log("\(kind.rawValue) ", terminator: "") emitQuantifier(kind: kind, arity: arity) } - print("repeating ", terminator: "", to: &standardError) + log("repeating ", terminator: "") emitRepeating(arity: arity) - print(to: &standardError) + log("") } - print("Generating atomic groups...", to: &standardError) + log("Generating atomic groups...") for arity in 0...maxArity { - print(" Arity \(arity): ", terminator: "", to: &standardError) + log(" Arity \(arity): ", terminator: "") emitAtomicGroup(arity: arity) - print(to: &standardError) + log("") } - print("Generating alternation overloads...", to: &standardError) + log("Generating alternation overloads...") for (leftArity, rightArity) in Permutations(totalArity: maxArity) { - print( - " Left arity: \(leftArity) Right arity: \(rightArity)", - to: &standardError) + log(" Left arity: \(leftArity) Right arity: \(rightArity)") emitAlternation(leftArity: leftArity, rightArity: rightArity) } - print("Generating 'AlternationBuilder.buildBlock(_:)' overloads...", to: &standardError) + log("Generating 'AlternationBuilder.buildBlock(_:)' overloads...") for arity in 1...maxArity { - print(" Capture arity: \(arity)", to: &standardError) + log(" Capture arity: \(arity)") emitUnaryAlternationBuildBlock(arity: arity) } - print("Generating 'capture' and 'tryCapture' overloads...", to: &standardError) + log("Generating 'capture' and 'tryCapture' overloads...") for arity in 0...maxArity { - print(" Capture arity: \(arity)", to: &standardError) + log(" Capture arity: \(arity)") emitCapture(arity: arity) } @@ -186,7 +191,7 @@ struct VariadicsGenerator: ParsableCommand { output("// END AUTO-GENERATED CONTENT\n") - print("Done!", to: &standardError) + log("Done!") } func tupleType(arity: Int, genericParameters: () -> String) -> String { From 7b737e3659a7431024ad2558a3b8413bcfe571b5 Mon Sep 17 00:00:00 2001 From: Tina Liu <49205802+itingliu@users.noreply.github.com> Date: Sun, 24 Apr 2022 14:09:31 -0700 Subject: [PATCH 100/133] Add `@RegexComponentBuilder` overloads for string processing algorithm. (#334) * Add `@RegexComponentBuilder` overloads for string processing algorithm. These overloads will allow you to write, e.g. ```swift let _ = str.wholeMatch { OneOrMore("a") "+" OneOrMore("a") } ``` instead of ```swift let _ = str.wholeMatch(of: Regex { OneOrMore("a") "+" OneOrMore("a") }) ``` --- .../Evolution/StringProcessingAlgorithms.md | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/Documentation/Evolution/StringProcessingAlgorithms.md b/Documentation/Evolution/StringProcessingAlgorithms.md index 6c591c268..0539d46ca 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -245,6 +245,16 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: `true` if the regex was found in the collection, otherwise /// `false`. public func contains(_ regex: some RegexComponent) -> Bool + + /// Returns a Boolean value indicating whether the collection contains the + /// given regex. + /// - Parameter content: A closure to produce a `RegexComponent` to search for + /// within this collection. + /// - Returns: `true` if the regex was found in the collection, otherwise + /// `false`. + public func contains( + @RegexComponentBuilder _ content: () -> some RegexComponent + ) -> Bool } ``` @@ -258,6 +268,15 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: `true` if the initial elements of the sequence matches the /// beginning of `regex`; otherwise, `false`. public func starts(with regex: some RegexComponent) -> Bool + + /// Returns a Boolean value indicating whether the initial elements of the + /// sequence are the same as the elements in the specified regex. + /// - Parameter content: A closure to produce a `RegexComponent` to compare. + /// - Returns: `true` if the initial elements of the sequence matches the + /// beginning of `regex`; otherwise, `false`. + public func starts( + @RegexComponentBuilder with content: () -> some RegexComponent + ) -> Bool } ``` @@ -324,6 +343,15 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: A new subsequence containing the elements of the collection /// that does not match `prefix` from the start. public func trimmingPrefix(_ regex: some RegexComponent) -> SubSequence + + /// Returns a new collection of the same type by removing `prefix` from the + /// start. + /// - Parameter _content A closure to produce a `RegexComponent` to be removed. + /// - Returns: A collection containing the elements that does not match + /// `prefix` from the start. + public func trimmingPrefix( + @RegexComponentBuilder _ content: () -> some RegexComponent + ) -> SubSequence } extension RangeReplaceableCollection @@ -332,6 +360,12 @@ extension RangeReplaceableCollection /// Removes the initial elements that matches the given regex. /// - Parameter regex: The regex to remove from this collection. public mutating func trimPrefix(_ regex: some RegexComponent) + + /// Removes the initial elements that matches the given regex. + /// - Parameter content: A closure to produce a `RegexComponent` to be removed. + public mutating func trimPrefix( + @RegexComponentBuilder _ content: () -> some RegexComponent + ) } ``` @@ -365,6 +399,16 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: A range in the collection of the first occurrence of `regex`. /// Returns `nil` if `regex` is not found. public func firstRange(of regex: some RegexComponent) -> Range? + + /// Finds and returns the range of the first occurrence of a given regex + /// within the collection. + /// - Parameter content: A closure to produce a `RegexComponent` to search for + /// within this collection. + /// - Returns: A range in the collection of the first occurrence of regex. + /// Returns `nil` if not found. + public func firstRange( + @RegexComponentBuilder of content: () -> some RegexComponent + ) -> Range? } ``` @@ -388,6 +432,16 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: A collection or ranges in the receiver of all occurrences of /// `regex`. Returns an empty collection if `regex` is not found. public func ranges(of regex: some RegexComponent) -> some Collection> + + /// Finds and returns the ranges of the all occurrences of a given sequence + /// within the collection. + /// - Parameter content: A closure to produce a `RegexComponent` to search for + /// within this collection. + /// - Returns: A collection or ranges in the receiver of all occurrences of + /// regex. Returns an empty collection if not found. + public func ranges( + @RegexComponentBuilder of content: () -> some RegexComponent + ) -> some Collection> } ``` @@ -401,15 +455,37 @@ extension BidirectionalCollection where SubSequence == Substring { /// there isn't a match. public func firstMatch(of regex: R) -> Regex.Match? + /// Returns the first match of the specified regex within the collection. + /// - Parameter content: A closure to produce a `RegexComponent` to search for. + /// - Returns: The first match of regex in the collection, or `nil` if + /// there isn't a match. + public func firstMatch( + @RegexComponentBuilder of content: () -> R + ) -> Regex.Match? + /// Match a regex in its entirety. /// - Parameter regex: The regex to match against. /// - Returns: The match if there is one, or `nil` if none. public func wholeMatch(of regex: R) -> Regex.Match? + /// Match a regex in its entirety. + /// - Parameter content: A closure to produce a `RegexComponent` to match against. + /// - Returns: The match if there is one, or `nil` if none. + public func wholeMatch( + @RegexComponentBuilder of content: () -> R + ) -> Regex.Match? + /// Match part of the regex, starting at the beginning. /// - Parameter regex: The regex to match against. /// - Returns: The match if there is one, or `nil` if none. public func prefixMatch(of regex: R) -> Regex.Match? + + /// Match part of the regex, starting at the beginning. + /// - Parameter content: A closure to produce a `RegexComponent` to match against. + /// - Returns: The match if there is one, or `nil` if none. + public func prefixMatch( + @RegexComponentBuilder of content: () -> R + ) -> Regex.Match? } ``` @@ -421,6 +497,13 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: The regex to search for. /// - Returns: A collection of matches of `regex`. public func matches(of regex: R) -> some Collection.Match> + + /// Returns a collection containing all matches of the specified regex. + /// - Parameter content: A closure to produce a `RegexComponent` to search for. + /// - Returns: A collection of matches of `regex`. + public func matches( + @RegexComponentBuilder of content: () -> R + ) -> some Collection.Match> } ``` @@ -490,6 +573,23 @@ extension RangeReplaceableCollection where SubSequence == Substring { subrange: Range, maxReplacements: Int = .max ) -> Self where Replacement.Element == Element + + /// Returns a new collection in which all occurrences of a sequence matching + /// the given regex are replaced by another collection. + /// - Parameters: + /// - replacement: The new elements to add to the collection. + /// - subrange: The range in the collection in which to search for `regex`. + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - content: A closure to produce a `RegexComponent` to replace. + /// - Returns: A new collection in which all occurrences of subsequence + /// matching `regex` in `subrange` are replaced by `replacement`. + public func replacing( + with replacement: Replacement, + subrange: Range, + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> some RegexComponent + ) -> Self where Replacement.Element == Element /// Returns a new collection in which all occurrences of a sequence matching /// the given regex are replaced by another collection. @@ -506,6 +606,21 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: Int = .max ) -> Self where Replacement.Element == Element + /// Returns a new collection in which all occurrences of a sequence matching + /// the given regex are replaced by another collection. + /// - Parameters: + /// - replacement: The new elements to add to the collection. + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - content: A closure to produce a `RegexComponent` to replace. + /// - Returns: A new collection in which all occurrences of subsequence + /// matching `regex` are replaced by `replacement`. + public func replacing( + with replacement: Replacement, + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> some RegexComponent + ) -> Self where Replacement.Element == Element + /// Replaces all occurrences of the sequence matching the given regex with /// a given collection. /// - Parameters: @@ -518,6 +633,19 @@ extension RangeReplaceableCollection where SubSequence == Substring { with replacement: Replacement, maxReplacements: Int = .max ) where Replacement.Element == Element + + /// Replaces all occurrences of the sequence matching the given regex with + /// a given collection. + /// - Parameters: + /// - replacement: The new elements to add to the collection. + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - content: A closure to produce a `RegexComponent` to replace. + public mutating func replace( + with replacement: Replacement, + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> some RegexComponent + ) -> Self where Replacement.Element == Element /// Returns a new collection in which all occurrences of a sequence matching /// the given regex are replaced by another regex match. @@ -536,6 +664,24 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: Int = .max, with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element + + /// Returns a new collection in which all occurrences of a sequence matching + /// the given regex are replaced by another regex match. + /// - Parameters: + /// - subrange: The range in the collection in which to search for `regex`. + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - content: A closure to produce a `RegexComponent` to replace. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. + /// - Returns: A new collection in which all occurrences of subsequence + /// matching `regex` are replaced by `replacement`. + public func replacing( + subrange: Range, + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> R, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows -> Self where Replacement.Element == Element /// Returns a new collection in which all occurrences of a sequence matching /// the given regex are replaced by another collection. @@ -552,6 +698,22 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: Int = .max, with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element + + /// Returns a new collection in which all occurrences of a sequence matching + /// the given regex are replaced by another collection. + /// - Parameters: + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - content: A closure to produce a `RegexComponent` to replace. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. + /// - Returns: A new collection in which all occurrences of subsequence + /// matching `regex` are replaced by `replacement`. + public func replacing( + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> R, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows -> Self where Replacement.Element == Element /// Replaces all occurrences of the sequence matching the given regex with /// a given collection. @@ -566,6 +728,20 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: Int = .max, with replacement: (Regex.Match) throws -> Replacement ) rethrows where Replacement.Element == Element + + /// Replaces all occurrences of the sequence matching the given regex with + /// a given collection. + /// - Parameters: + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - content: A closure to produce a `RegexComponent` to replace. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. + public mutating func replace( + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> R, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows where Replacement.Element == Element } ``` @@ -613,6 +789,25 @@ extension BidirectionalCollection where SubSequence == Substring { maxSplits: Int = Int.max, omittingEmptySubsequences: Bool = true ) -> some Collection + + /// Returns the longest possible subsequences of the collection, in order, + /// around subsequence that match the given separator regex. + /// + /// - Parameters: + /// - maxSplits: The maximum number of times to split the collection, + /// or one less than the number of subsequences to return. + /// - omittingEmptySubsequences: If `false`, an empty subsequence is + /// returned in the result for each consecutive pair of matches + /// and for each match at the start or end of the collection. If + /// `true`, only nonempty subsequences are returned. + /// - separator: A closure to produce a `RegexComponent` to be split upon. + /// - Returns: A collection of substrings, split from this collection's + /// elements. + public func split( + maxSplits: Int = Int.max, + omittingEmptySubsequences: Bool = true, + @RegexComponentBuilder separator: () -> some RegexComponent + ) -> some Collection } ``` From c56dc7673a1e28b7807e0682a525046a7a535651 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 22 Apr 2022 16:24:36 -0500 Subject: [PATCH 101/133] Remove @testable annotations where possible --- Tests/RegexBuilderTests/RegexDSLTests.swift | 2 +- .../RegexTests/AlgorithmsInternalsTests.swift | 47 +++++++++++++++++++ Tests/RegexTests/AlgorithmsTests.swift | 33 +------------ Tests/RegexTests/AllScalarsTests.swift | 2 +- Tests/RegexTests/CompileTests.swift | 1 - 5 files changed, 50 insertions(+), 35 deletions(-) create mode 100644 Tests/RegexTests/AlgorithmsInternalsTests.swift diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 7c06fd6c3..42cb9c52e 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -11,7 +11,7 @@ import XCTest import _StringProcessing -@testable import RegexBuilder +import RegexBuilder class RegexDSLTests: XCTestCase { func _testDSLCaptures( diff --git a/Tests/RegexTests/AlgorithmsInternalsTests.swift b/Tests/RegexTests/AlgorithmsInternalsTests.swift new file mode 100644 index 000000000..f0d556744 --- /dev/null +++ b/Tests/RegexTests/AlgorithmsInternalsTests.swift @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +@testable import _StringProcessing +import XCTest + +// TODO: Protocol-powered testing +extension AlgorithmTests { + func testAdHoc() { + let r = try! Regex("a|b+") + + XCTAssert("palindrome".contains(r)) + XCTAssert("botany".contains(r)) + XCTAssert("antiquing".contains(r)) + XCTAssertFalse("cdef".contains(r)) + + let str = "a string with the letter b in it" + let first = str.firstRange(of: r) + let last = str.lastRange(of: r) + let (expectFirst, expectLast) = ( + str.index(atOffset: 0).. Date: Fri, 22 Apr 2022 19:05:50 -0500 Subject: [PATCH 102/133] Switch FixedPatternConsumer to be over Sequence --- .../Consumers/FixedPatternConsumer.swift | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Sources/_StringProcessing/Algorithms/Consumers/FixedPatternConsumer.swift b/Sources/_StringProcessing/Algorithms/Consumers/FixedPatternConsumer.swift index e611f477a..8312c247a 100644 --- a/Sources/_StringProcessing/Algorithms/Consumers/FixedPatternConsumer.swift +++ b/Sources/_StringProcessing/Algorithms/Consumers/FixedPatternConsumer.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -struct FixedPatternConsumer +struct FixedPatternConsumer where Consumed.Element: Equatable, Pattern.Element == Consumed.Element { let pattern: Pattern @@ -21,20 +21,17 @@ extension FixedPatternConsumer: CollectionConsumer { in range: Range ) -> Consumed.Index? { var index = range.lowerBound - var patternIndex = pattern.startIndex + var patternIterator = pattern.makeIterator() - while true { - if patternIndex == pattern.endIndex { - return index - } - - if index == range.upperBound || consumed[index] != pattern[patternIndex] { + while let element = patternIterator.next() { + if index == range.upperBound || consumed[index] != element { return nil } consumed.formIndex(after: &index) - pattern.formIndex(after: &patternIndex) } + + return index } } From caad657fe300cee414979093387955480c310969 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 22 Apr 2022 19:19:08 -0500 Subject: [PATCH 103/133] Update Sequence/Collection constraints --- .../Algorithms/Algorithms/Contains.swift | 8 ++--- .../Algorithms/Algorithms/FirstRange.swift | 28 ++++++++------- .../Algorithms/Algorithms/Ranges.swift | 19 +++++----- .../Algorithms/Algorithms/Replace.swift | 36 +++++++++---------- .../Algorithms/Algorithms/Split.swift | 6 ++-- .../Algorithms/Algorithms/Trim.swift | 6 ++-- 6 files changed, 53 insertions(+), 50 deletions(-) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift index 1d4332ad0..96414423a 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift @@ -28,16 +28,16 @@ extension Collection where Element: Equatable { /// - Returns: `true` if the collection contains the specified sequence, /// otherwise `false`. @available(SwiftStdlib 5.7, *) - public func contains(_ other: S) -> Bool - where S.Element == Element + public func contains(_ other: C) -> Bool + where C.Element == Element { firstRange(of: other) != nil } } extension BidirectionalCollection where Element: Comparable { - func contains(_ other: S) -> Bool - where S.Element == Element + func contains(_ other: C) -> Bool + where C.Element == Element { if #available(SwiftStdlib 5.7, *) { return firstRange(of: other) != nil diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift index 508c04663..42703827e 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift @@ -32,31 +32,33 @@ extension BidirectionalCollection { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { - /// Finds and returns the range of the first occurrence of a given sequence - /// within the collection. - /// - Parameter sequence: The sequence to search for. + /// Finds and returns the range of the first occurrence of a given collection + /// within this collection. + /// + /// - Parameter other: The collection to search for. /// - Returns: A range in the collection of the first occurrence of `sequence`. /// Returns nil if `sequence` is not found. @available(SwiftStdlib 5.7, *) - public func firstRange( - of sequence: S - ) -> Range? where S.Element == Element { + public func firstRange( + of other: C + ) -> Range? where C.Element == Element { // TODO: Use a more efficient search algorithm - let searcher = ZSearcher(pattern: Array(sequence), by: ==) + let searcher = ZSearcher(pattern: Array(other), by: ==) return searcher.search(self[...], in: startIndex..( - of other: S - ) -> Range? where S.Element == Element { + public func firstRange( + of other: C + ) -> Range? where C.Element == Element { let searcher = PatternOrEmpty( searcher: TwoWaySearcher(pattern: Array(other))) let slice = self[...] diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift index 853c73271..33a9748ac 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift @@ -175,9 +175,9 @@ extension BidirectionalCollection { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { - func ranges( - of other: S - ) -> RangesCollection> where S.Element == Element { + func ranges( + of other: C + ) -> RangesCollection> where C.Element == Element { ranges(of: ZSearcher(pattern: Array(other), by: ==)) } @@ -188,9 +188,9 @@ extension Collection where Element: Equatable { /// - Returns: A collection of ranges of all occurrences of `other`. Returns /// an empty collection if `other` is not found. @available(SwiftStdlib 5.7, *) - public func ranges( - of other: S - ) -> [Range] where S.Element == Element { + public func ranges( + of other: C + ) -> [Range] where C.Element == Element { ranges(of: ZSearcher(pattern: Array(other), by: ==)).map { $0 } } } @@ -207,10 +207,10 @@ extension BidirectionalCollection where Element: Equatable { } extension BidirectionalCollection where Element: Comparable { - func ranges( - of other: S + func ranges( + of other: C ) -> RangesCollection>> - where S.Element == Element + where C.Element == Element { ranges(of: PatternOrEmpty(searcher: TwoWaySearcher(pattern: Array(other)))) } @@ -247,6 +247,7 @@ extension BidirectionalCollection where SubSequence == Substring { // FIXME: Return `some Collection>` for SE-0346 /// Finds and returns the ranges of the all occurrences of a given sequence /// within the collection. + /// /// - Parameter regex: The regex to search for. /// - Returns: A collection or ranges in the receiver of all occurrences of /// `regex`. Returns an empty collection if `regex` is not found. diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift index 4a6da6c10..217fb90d6 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift @@ -78,12 +78,12 @@ extension RangeReplaceableCollection where Element: Equatable { /// - Returns: A new collection in which all occurrences of `other` in /// `subrange` of the collection are replaced by `replacement`. @available(SwiftStdlib 5.7, *) - public func replacing( - _ other: S, + public func replacing( + _ other: C, with replacement: Replacement, subrange: Range, maxReplacements: Int = .max - ) -> Self where S.Element == Element, Replacement.Element == Element { + ) -> Self where C.Element == Element, Replacement.Element == Element { replacing( ZSearcher(pattern: Array(other), by: ==), with: replacement, @@ -101,11 +101,11 @@ extension RangeReplaceableCollection where Element: Equatable { /// - Returns: A new collection in which all occurrences of `other` in /// `subrange` of the collection are replaced by `replacement`. @available(SwiftStdlib 5.7, *) - public func replacing( - _ other: S, + public func replacing( + _ other: C, with replacement: Replacement, maxReplacements: Int = .max - ) -> Self where S.Element == Element, Replacement.Element == Element { + ) -> Self where C.Element == Element, Replacement.Element == Element { replacing( other, with: replacement, @@ -120,11 +120,11 @@ extension RangeReplaceableCollection where Element: Equatable { /// - maxReplacements: A number specifying how many occurrences of `other` /// to replace. Default is `Int.max`. @available(SwiftStdlib 5.7, *) - public mutating func replace( - _ other: S, + public mutating func replace( + _ other: C, with replacement: Replacement, maxReplacements: Int = .max - ) where S.Element == Element, Replacement.Element == Element { + ) where C.Element == Element, Replacement.Element == Element { self = replacing( other, with: replacement, @@ -136,12 +136,12 @@ extension RangeReplaceableCollection where Element: Equatable { extension RangeReplaceableCollection where Self: BidirectionalCollection, Element: Comparable { - func replacing( - _ other: S, + func replacing( + _ other: C, with replacement: Replacement, subrange: Range, maxReplacements: Int = .max - ) -> Self where S.Element == Element, Replacement.Element == Element { + ) -> Self where C.Element == Element, Replacement.Element == Element { replacing( PatternOrEmpty(searcher: TwoWaySearcher(pattern: Array(other))), with: replacement, @@ -149,11 +149,11 @@ extension RangeReplaceableCollection maxReplacements: maxReplacements) } - func replacing( - _ other: S, + func replacing( + _ other: C, with replacement: Replacement, maxReplacements: Int = .max - ) -> Self where S.Element == Element, Replacement.Element == Element { + ) -> Self where C.Element == Element, Replacement.Element == Element { replacing( other, with: replacement, @@ -161,11 +161,11 @@ extension RangeReplaceableCollection maxReplacements: maxReplacements) } - mutating func replace( - _ other: S, + mutating func replace( + _ other: C, with replacement: Replacement, maxReplacements: Int = .max - ) where S.Element == Element, Replacement.Element == Element { + ) where C.Element == Element, Replacement.Element == Element { self = replacing( other, with: replacement, diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift index 8c7a9832d..4fd0081bb 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -266,10 +266,10 @@ extension BidirectionalCollection where Element: Equatable { } extension BidirectionalCollection where Element: Comparable { - func split( - by separator: S + func split( + by separator: C ) -> SplitCollection>> - where S.Element == Element + where C.Element == Element { split( by: PatternOrEmpty(searcher: TwoWaySearcher(pattern: Array(separator)))) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift index 73a5cd554..0d7bde56b 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift @@ -188,7 +188,7 @@ extension Collection where Element: Equatable { /// - Returns: A collection containing the elements of the collection that are /// not removed by `predicate`. @available(SwiftStdlib 5.7, *) - public func trimmingPrefix( + public func trimmingPrefix( _ prefix: Prefix ) -> SubSequence where Prefix.Element == Element { trimmingPrefix(FixedPatternConsumer(pattern: prefix)) @@ -202,7 +202,7 @@ extension Collection where SubSequence == Self, Element: Equatable { /// as its argument and returns a Boolean value indicating whether the /// element should be removed from the collection. @available(SwiftStdlib 5.7, *) - public mutating func trimPrefix( + public mutating func trimPrefix( _ prefix: Prefix ) where Prefix.Element == Element { trimPrefix(FixedPatternConsumer(pattern: prefix)) @@ -217,7 +217,7 @@ extension RangeReplaceableCollection where Element: Equatable { /// as its argument and returns a Boolean value indicating whether the /// element should be removed from the collection. @available(SwiftStdlib 5.7, *) - public mutating func trimPrefix( + public mutating func trimPrefix( _ prefix: Prefix ) where Prefix.Element == Element { trimPrefix(FixedPatternConsumer(pattern: prefix)) From b7a021fdfa69b98879ddec371125c7675b66688e Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 22 Apr 2022 19:20:27 -0500 Subject: [PATCH 104/133] Update trim(while:) - rethrowing and nonescaping This eliminates PredicateConsumer from the implementation so that the closure can throw. --- .../Algorithms/Algorithms/Trim.swift | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift index 0d7bde56b..7411236da 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift @@ -102,21 +102,26 @@ extension RangeReplaceableCollection where Self: BidirectionalCollection { // MARK: Predicate algorithms extension Collection { - // TODO: Non-escaping and throwing - func trimmingPrefix( - while predicate: @escaping (Element) -> Bool - ) -> SubSequence { - trimmingPrefix(ManyConsumer(base: PredicateConsumer(predicate: predicate))) + fileprivate func endOfPrefix(while predicate: (Element) throws -> Bool) rethrows -> Index { + try firstIndex(where: { try !predicate($0) }) ?? endIndex + } + + @available(SwiftStdlib 5.7, *) + public func trimmingPrefix( + while predicate: (Element) throws -> Bool + ) rethrows -> SubSequence { + let end = try endOfPrefix(while: predicate) + return self[end...] } } extension Collection where SubSequence == Self { @available(SwiftStdlib 5.7, *) public mutating func trimPrefix( - while predicate: @escaping (Element) -> Bool - ) { - trimPrefix(ManyConsumer( - base: PredicateConsumer(predicate: predicate))) + while predicate: (Element) throws -> Bool + ) throws { + let end = try endOfPrefix(while: predicate) + self = self[end...] } } @@ -124,9 +129,10 @@ extension RangeReplaceableCollection { @_disfavoredOverload @available(SwiftStdlib 5.7, *) public mutating func trimPrefix( - while predicate: @escaping (Element) -> Bool - ) { - trimPrefix(ManyConsumer(base: PredicateConsumer(predicate: predicate))) + while predicate: (Element) throws -> Bool + ) rethrows { + let end = try endOfPrefix(while: predicate) + removeSubrange(startIndex.. Date: Fri, 22 Apr 2022 19:21:34 -0500 Subject: [PATCH 105/133] Add tests for trim methods --- Tests/RegexTests/AlgorithmsTests.swift | 55 ++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/Tests/RegexTests/AlgorithmsTests.swift b/Tests/RegexTests/AlgorithmsTests.swift index 21095b4c3..b5f197950 100644 --- a/Tests/RegexTests/AlgorithmsTests.swift +++ b/Tests/RegexTests/AlgorithmsTests.swift @@ -24,6 +24,14 @@ func output(_ s: @autoclosure () -> T) { } } +func makeSingleUseSequence(element: T, count: Int) -> UnfoldSequence { + var count = count + return sequence(state: ()) { _ in + defer { count -= 1 } + return count > 0 ? element : nil + } +} + class RegexConsumerTests: XCTestCase { func testRanges() { func expectRanges( @@ -79,6 +87,53 @@ class RegexConsumerTests: XCTestCase { expectSplit("a", "", ["", "a", ""]) expectSplit("a", "x", ["a"]) expectSplit("a", "a", ["", ""]) + + func testTrim() { + func expectTrim( + _ string: String, + _ regex: String, + _ expected: Substring, + file: StaticString = #file, line: UInt = #line + ) { + let regex = try! Regex(regex) + let actual = string.trimmingPrefix(regex) + XCTAssertEqual(actual, expected, file: file, line: line) + } + + expectTrim("", "", "") + expectTrim("", "x", "") + expectTrim("a", "", "a") + expectTrim("a", "x", "a") + expectTrim("___a", "_", "__a") + expectTrim("___a", "_+", "a") + + XCTAssertEqual("".trimmingPrefix("a"), "") + XCTAssertEqual("a".trimmingPrefix("a"), "") + XCTAssertEqual("b".trimmingPrefix("a"), "b") + XCTAssertEqual("a".trimmingPrefix(""), "a") + XCTAssertEqual("___a".trimmingPrefix("_"), "__a") + XCTAssertEqual("___a".trimmingPrefix("___"), "a") + XCTAssertEqual("___a".trimmingPrefix("____"), "___a") + XCTAssertEqual("___a".trimmingPrefix("___a"), "") + + do { + let prefix = makeSingleUseSequence(element: "_" as Character, count: 5) + XCTAssertEqual("_____a".trimmingPrefix(prefix), "a") + XCTAssertEqual("_____a".trimmingPrefix(prefix), "_____a") + } + do { + let prefix = makeSingleUseSequence(element: "_" as Character, count: 5) + XCTAssertEqual("a".trimmingPrefix(prefix), "a") + // The result of this next call is technically undefined, so this + // is just to test that it doesn't crash. + XCTAssertNotEqual("_____a".trimmingPrefix(prefix), "") + } + + XCTAssertEqual("".trimmingPrefix(while: \.isWhitespace), "") + XCTAssertEqual("a".trimmingPrefix(while: \.isWhitespace), "a") + XCTAssertEqual(" ".trimmingPrefix(while: \.isWhitespace), "") + XCTAssertEqual(" a".trimmingPrefix(while: \.isWhitespace), "a") + XCTAssertEqual("a ".trimmingPrefix(while: \.isWhitespace), "a ") } func testReplace() { From d6a01e7b2e7c9df4b10a94001e07f7599cf97198 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Sat, 23 Apr 2022 00:56:45 -0500 Subject: [PATCH 106/133] Add maxSplits and omitEmpty to split methods This plumbs those parameters down into the SplitCollection type, and removes Collection conformance for now because (a) we aren't using it, and (b) it looks tricky to implement properly. --- .../Algorithms/Algorithms/Split.swift | 266 +++++++++++------- Tests/RegexTests/AlgorithmsTests.swift | 84 +++++- 2 files changed, 251 insertions(+), 99 deletions(-) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift index 4fd0081bb..97d8c80dd 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -15,13 +15,28 @@ struct SplitCollection { public typealias Base = Searcher.Searched let ranges: RangesCollection - - init(ranges: RangesCollection) { + var maxSplits: Int + var omittingEmptySubsequences: Bool + + init( + ranges: RangesCollection, + maxSplits: Int, + omittingEmptySubsequences: Bool) + { self.ranges = ranges + self.maxSplits = maxSplits + self.omittingEmptySubsequences = omittingEmptySubsequences } - init(base: Base, searcher: Searcher) { + init( + base: Base, + searcher: Searcher, + maxSplits: Int, + omittingEmptySubsequences: Bool) + { self.ranges = base.ranges(of: searcher) + self.maxSplits = maxSplits + self.omittingEmptySubsequences = omittingEmptySubsequences } } @@ -30,97 +45,127 @@ extension SplitCollection: Sequence { let base: Base var index: Base.Index var ranges: RangesCollection.Iterator - var isDone: Bool - - init(ranges: RangesCollection) { + var maxSplits: Int + var omittingEmptySubsequences: Bool + + var splitCounter = 0 + var isDone = false + + init( + ranges: RangesCollection, + maxSplits: Int, + omittingEmptySubsequences: Bool + ) { self.base = ranges.base self.index = base.startIndex self.ranges = ranges.makeIterator() - self.isDone = false + self.maxSplits = maxSplits + self.omittingEmptySubsequences = omittingEmptySubsequences } public mutating func next() -> Base.SubSequence? { guard !isDone else { return nil } - guard let range = ranges.next() else { + /// Return the rest of base if it's non-empty or we're including + /// empty subsequences. + func finish() -> Base.SubSequence? { isDone = true - return base[index...] + return index == base.endIndex && omittingEmptySubsequences + ? nil + : base[index...] + } + + if splitCounter >= maxSplits { + return finish() } - defer { index = range.upperBound } - return base[index.. Iterator { - Iterator(ranges: ranges) - } -} - -extension SplitCollection: Collection { - public struct Index { - var start: Base.Index - var base: RangesCollection.Index - var isEndIndex: Bool - } - - public var startIndex: Index { - let base = ranges.startIndex - return Index(start: ranges.base.startIndex, base: base, isEndIndex: false) - } - - public var endIndex: Index { - Index(start: ranges.base.endIndex, base: ranges.endIndex, isEndIndex: true) - } - - public func formIndex(after index: inout Index) { - guard !index.isEndIndex else { fatalError("Cannot advance past endIndex") } - - if let range = index.base.range { - let newStart = range.upperBound - ranges.formIndex(after: &index.base) - index.start = newStart - } else { - index.isEndIndex = true - } - } - - public func index(after index: Index) -> Index { - var index = index - formIndex(after: &index) - return index - } - - public subscript(index: Index) -> Base.SubSequence { - guard !index.isEndIndex else { - fatalError("Cannot subscript using endIndex") - } - let end = index.base.range?.lowerBound ?? ranges.base.endIndex - return ranges.base[index.start.. Bool { - switch (lhs.isEndIndex, rhs.isEndIndex) { - case (false, false): - return lhs.start == rhs.start - case (let lhs, let rhs): - return lhs == rhs - } - } - - static func < (lhs: Self, rhs: Self) -> Bool { - switch (lhs.isEndIndex, rhs.isEndIndex) { - case (true, _): - return false - case (_, true): - return true - case (false, false): - return lhs.start < rhs.start - } - } -} +//extension SplitCollection: Collection { +// public struct Index { +// var start: Base.Index +// var base: RangesCollection.Index +// var isEndIndex: Bool +// } +// +// public var startIndex: Index { +// let base = ranges.startIndex +// return Index(start: ranges.base.startIndex, base: base, isEndIndex: false) +// } +// +// public var endIndex: Index { +// Index(start: ranges.base.endIndex, base: ranges.endIndex, isEndIndex: true) +// } +// +// public func formIndex(after index: inout Index) { +// guard !index.isEndIndex else { fatalError("Cannot advance past endIndex") } +// +// if let range = index.base.range { +// let newStart = range.upperBound +// ranges.formIndex(after: &index.base) +// index.start = newStart +// } else { +// index.isEndIndex = true +// } +// } +// +// public func index(after index: Index) -> Index { +// var index = index +// formIndex(after: &index) +// return index +// } +// +// public subscript(index: Index) -> Base.SubSequence { +// guard !index.isEndIndex else { +// fatalError("Cannot subscript using endIndex") +// } +// let end = index.base.range?.lowerBound ?? ranges.base.endIndex +// return ranges.base[index.start.. Bool { +// switch (lhs.isEndIndex, rhs.isEndIndex) { +// case (false, false): +// return lhs.start == rhs.start +// case (let lhs, let rhs): +// return lhs == rhs +// } +// } +// +// static func < (lhs: Self, rhs: Self) -> Bool { +// switch (lhs.isEndIndex, rhs.isEndIndex) { +// case (true, _): +// return false +// case (_, true): +// return true +// case (false, false): +// return lhs.start < rhs.start +// } +// } +//} // MARK: `ReversedSplitCollection` @@ -176,10 +221,15 @@ extension ReversedSplitCollection: Sequence { extension Collection { func split( - by separator: Searcher + by separator: Searcher, + maxSplits: Int, + omittingEmptySubsequences: Bool ) -> SplitCollection where Searcher.Searched == Self { - // TODO: `maxSplits`, `omittingEmptySubsequences`? - SplitCollection(base: self, searcher: separator) + SplitCollection( + base: self, + searcher: separator, + maxSplits: maxSplits, + omittingEmptySubsequences: omittingEmptySubsequences) } } @@ -198,9 +248,11 @@ extension BidirectionalCollection { extension Collection { // TODO: Non-escaping and throwing func split( - whereSeparator predicate: @escaping (Element) -> Bool + whereSeparator predicate: @escaping (Element) -> Bool, + maxSplits: Int, + omittingEmptySubsequences: Bool ) -> SplitCollection> { - split(by: PredicateConsumer(predicate: predicate)) + split(by: PredicateConsumer(predicate: predicate), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) } } @@ -216,9 +268,11 @@ extension BidirectionalCollection where Element: Equatable { extension Collection where Element: Equatable { func split( - by separator: Element + by separator: Element, + maxSplits: Int, + omittingEmptySubsequences: Bool ) -> SplitCollection> { - split(whereSeparator: { $0 == separator }) + split(whereSeparator: { $0 == separator }, maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) } } @@ -234,10 +288,12 @@ extension BidirectionalCollection where Element: Equatable { extension Collection where Element: Equatable { @_disfavoredOverload - func split( - by separator: S - ) -> SplitCollection> where S.Element == Element { - split(by: ZSearcher(pattern: Array(separator), by: ==)) + func split( + by separator: C, + maxSplits: Int, + omittingEmptySubsequences: Bool + ) -> SplitCollection> where C.Element == Element { + split(by: ZSearcher(pattern: Array(separator), by: ==), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) } // FIXME: Return `some Collection` for SE-0346 @@ -247,10 +303,12 @@ extension Collection where Element: Equatable { /// - Returns: A collection of subsequences, split from this collection's /// elements. @available(SwiftStdlib 5.7, *) - public func split( - by separator: S - ) -> [SubSequence] where S.Element == Element { - Array(split(by: ZSearcher(pattern: Array(separator), by: ==))) + public func split( + separator: C, + maxSplits: Int = .max, + omittingEmptySubsequences: Bool = true + ) -> [SubSequence] where C.Element == Element { + Array(split(by: ZSearcher(pattern: Array(separator), by: ==), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences)) } } @@ -267,12 +325,15 @@ extension BidirectionalCollection where Element: Equatable { extension BidirectionalCollection where Element: Comparable { func split( - by separator: C + by separator: C, + maxSplits: Int, + omittingEmptySubsequences: Bool ) -> SplitCollection>> where C.Element == Element { split( - by: PatternOrEmpty(searcher: TwoWaySearcher(pattern: Array(separator)))) + by: PatternOrEmpty(searcher: TwoWaySearcher(pattern: Array(separator))), + maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) } // FIXME @@ -292,9 +353,11 @@ extension BidirectionalCollection where Element: Comparable { extension BidirectionalCollection where SubSequence == Substring { @_disfavoredOverload func split( - by separator: R + by separator: R, + maxSplits: Int, + omittingEmptySubsequences: Bool ) -> SplitCollection> { - split(by: RegexConsumer(separator)) + split(by: RegexConsumer(separator), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) } func splitFromBack( @@ -303,15 +366,22 @@ extension BidirectionalCollection where SubSequence == Substring { splitFromBack(by: RegexConsumer(separator)) } - // FIXME: Return `some Collection` for SE-0346 + // TODO: Is this @_disfavoredOverload necessary? + // It prevents split(separator: String) from choosing this overload instead + // of the collection-based version when String has RegexComponent conformance + + // FIXME: Return `some Collection` for SE-0346 /// Returns the longest possible subsequences of the collection, in order, /// around elements equal to the given separator. /// - Parameter separator: A regex describing elements to be split upon. /// - Returns: A collection of substrings, split from this collection's /// elements. + @_disfavoredOverload public func split( - by separator: R + separator: R, + maxSplits: Int = .max, + omittingEmptySubsequences: Bool = true ) -> [SubSequence] { - Array(split(by: RegexConsumer(separator))) + Array(split(by: RegexConsumer(separator), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences)) } } diff --git a/Tests/RegexTests/AlgorithmsTests.swift b/Tests/RegexTests/AlgorithmsTests.swift index b5f197950..8e424aa13 100644 --- a/Tests/RegexTests/AlgorithmsTests.swift +++ b/Tests/RegexTests/AlgorithmsTests.swift @@ -78,7 +78,7 @@ class RegexConsumerTests: XCTestCase { file: StaticString = #file, line: UInt = #line ) { let regex = try! Regex(regex) - let actual = Array(string.split(by: regex)) + let actual = Array(string.split(separator: regex, omittingEmptySubsequences: false)) XCTAssertEqual(actual, expected, file: file, line: line) } @@ -87,6 +87,88 @@ class RegexConsumerTests: XCTestCase { expectSplit("a", "", ["", "a", ""]) expectSplit("a", "x", ["a"]) expectSplit("a", "a", ["", ""]) + expectSplit("a____a____a", "_+", ["a", "a", "a"]) + expectSplit("____a____a____a____", "_+", ["", "a", "a", "a", ""]) + } + + func testSplitPermutations() throws { + let splitRegex = try Regex(#"\|"#) + XCTAssertEqual( + "a|a|||a|a".split(separator: splitRegex), + ["a", "a", "a", "a"]) + XCTAssertEqual( + "a|a|||a|a".split(separator: splitRegex, omittingEmptySubsequences: false), + ["a", "a", "", "", "a", "a"]) + XCTAssertEqual( + "a|a|||a|a".split(separator: splitRegex, maxSplits: 2), + ["a", "a", "||a|a"]) + + XCTAssertEqual( + "a|a|||a|a|||a|a|||".split(separator: "|||"), + ["a|a", "a|a", "a|a"]) + XCTAssertEqual( + "a|a|||a|a|||a|a|||".split(separator: "|||", omittingEmptySubsequences: false), + ["a|a", "a|a", "a|a", ""]) + XCTAssertEqual( + "a|a|||a|a|||a|a|||".split(separator: "|||", maxSplits: 2), + ["a|a", "a|a", "a|a|||"]) + + XCTAssertEqual( + "aaaa".split(separator: ""), + ["a", "a", "a", "a"]) + XCTAssertEqual( + "aaaa".split(separator: "", omittingEmptySubsequences: false), + ["", "a", "a", "a", "a", ""]) + XCTAssertEqual( + "aaaa".split(separator: "", maxSplits: 2), + ["a", "a", "aa"]) + XCTAssertEqual( + "aaaa".split(separator: "", maxSplits: 2, omittingEmptySubsequences: false), + ["", "a", "aaa"]) + + // Fuzzing the input and parameters + for _ in 1...1_000 { + // Make strings that look like: + // "aaaaaaa" + // "|||aaaa||||" + // "a|a|aa|aa|" + // "|a||||aaa|a|||" + // "a|aa" + let keepCount = Int.random(in: 0...10) + let splitCount = Int.random(in: 0...10) + let str = [repeatElement("a", count: keepCount), repeatElement("|", count: splitCount)] + .joined() + .shuffled() + .joined() + + let omitEmpty = Bool.random() + let maxSplits = Bool.random() ? Int.max : Int.random(in: 0...10) + + // Use the stdlib behavior as the expected outcome + let expected = str.split( + separator: "|" as Character, + maxSplits: maxSplits, + omittingEmptySubsequences: omitEmpty) + let regexActual = str.split( + separator: splitRegex, + maxSplits: maxSplits, + omittingEmptySubsequences: omitEmpty) + let stringActual = str.split( + separator: "|" as String, + maxSplits: maxSplits, + omittingEmptySubsequences: omitEmpty) + XCTAssertEqual(regexActual, expected, """ + Mismatch in regex split of '\(str)', maxSplits: \(maxSplits), omitEmpty: \(omitEmpty) + expected: \(expected.map(String.init)) + actual: \(regexActual.map(String.init)) + """) + XCTAssertEqual(stringActual, expected, """ + Mismatch in string split of '\(str)', maxSplits: \(maxSplits), omitEmpty: \(omitEmpty) + expected: \(expected.map(String.init)) + actual: \(regexActual.map(String.init)) + """) + } + } func testTrim() { func expectTrim( From e81a8bd2a9395abf3180c6826272113078202bfb Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Sat, 23 Apr 2022 12:22:55 -0500 Subject: [PATCH 107/133] Add tests / fixes for contains / firstRange(of:) Better test coverage for both the regex and collection variants of these two methods, plus overloads for contains(_:) to win over Foundation's version from the overlay. Also fixes an error in TwoWaySearcher that tried to offset past the searched string's endIndex; might be a sign of something awry, but tests seem to be otherwise succeeding. --- .../Algorithms/Algorithms/Contains.swift | 14 ++++++ .../Algorithms/Searchers/TwoWaySearcher.swift | 9 +++- Tests/RegexTests/AlgorithmsTests.swift | 50 ++++++++++++++++++- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift index 96414423a..2a1ef72a2 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift @@ -46,6 +46,20 @@ extension BidirectionalCollection where Element: Comparable { } } +// Overload breakers + +extension StringProtocol { + @available(SwiftStdlib 5.7, *) + public func contains(_ other: String) -> Bool { + firstRange(of: other) != nil + } + + @available(SwiftStdlib 5.7, *) + public func contains(_ other: Substring) -> Bool { + firstRange(of: other) != nil + } +} + // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { diff --git a/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift b/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift index 5530b4421..ae613cfd7 100644 --- a/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift +++ b/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift @@ -47,8 +47,10 @@ extension TwoWaySearcher: CollectionSearcher { for searched: Searched, in range: Range ) -> State { + // FIXME: Is this 'limitedBy' requirement a sign of error? let criticalIndex = searched.index( - range.lowerBound, offsetBy: criticalIndex) + range.lowerBound, offsetBy: criticalIndex, limitedBy: range.upperBound) + ?? range.upperBound return State( end: range.upperBound, index: range.lowerBound, @@ -66,7 +68,10 @@ extension TwoWaySearcher: CollectionSearcher { let start = _searchLeft(searched, &state, end) { state.index = end - state.criticalIndex = searched.index(end, offsetBy: criticalIndex) + // FIXME: Is this 'limitedBy' requirement a sign of error? + state.criticalIndex = searched.index( + end, offsetBy: criticalIndex, limitedBy: searched.endIndex) + ?? searched.endIndex state.memory = nil return start..(element: T, count: Int) -> UnfoldSequence } } -class RegexConsumerTests: XCTestCase { +class AlgorithmTests: XCTestCase { + func testContains() { + XCTAssertTrue("".contains("")) + XCTAssertTrue("abcde".contains("")) + XCTAssertTrue("abcde".contains("abcd")) + XCTAssertTrue("abcde".contains("bcde")) + XCTAssertTrue("abcde".contains("bcd")) + XCTAssertTrue("ababacabababa".contains("abababa")) + + XCTAssertFalse("".contains("abcd")) + + for start in 0..<9 { + for end in start..<9 { + XCTAssertTrue((0..<10).contains(start...end)) + XCTAssertFalse((0..<10).contains(start...10)) + } + } + } + func testRanges() { func expectRanges( _ string: String, @@ -48,6 +66,9 @@ class RegexConsumerTests: XCTestCase { // `IndexingIterator` tests the collection conformance let actualCol: [Range] = string[...].ranges(of: regex)[...].map(string.offsets(of:)) XCTAssertEqual(actualCol, expected, file: file, line: line) + + let firstRange = string.firstRange(of: regex).map(string.offsets(of:)) + XCTAssertEqual(firstRange, expected.first, file: file, line: line) } expectRanges("", "", [0..<0]) @@ -68,6 +89,31 @@ class RegexConsumerTests: XCTestCase { expectRanges("abc", "(a|b)*", [0..<2, 2..<2, 3..<3]) expectRanges("abc", "(b|c)+", [1..<3]) expectRanges("abc", "(b|c)*", [0..<0, 1..<3, 3..<3]) + + func expectStringRanges( + _ input: String, + _ pattern: String, + _ expected: [Range], + file: StaticString = #file, line: UInt = #line + ) { + let actualSeq: [Range] = input.ranges(of: pattern).map(input.offsets(of:)) + XCTAssertEqual(actualSeq, expected, file: file, line: line) + + // `IndexingIterator` tests the collection conformance + let actualCol: [Range] = input.ranges(of: pattern)[...].map(input.offsets(of:)) + XCTAssertEqual(actualCol, expected, file: file, line: line) + + let firstRange = input.firstRange(of: pattern).map(input.offsets(of:)) + XCTAssertEqual(firstRange, expected.first, file: file, line: line) + } + + expectStringRanges("", "", [0..<0]) + expectStringRanges("abcde", "", [0..<0, 1..<1, 2..<2, 3..<3, 4..<4, 5..<5]) + expectStringRanges("abcde", "abcd", [0..<4]) + expectStringRanges("abcde", "bcde", [1..<5]) + expectStringRanges("abcde", "bcd", [1..<4]) + expectStringRanges("ababacabababa", "abababa", [6..<13]) + expectStringRanges("ababacabababa", "aba", [0..<3, 6..<9, 10..<13]) } func testSplit() { From 9e09bf8c8ee5aebe43be9ba6a9a73a0970eebbfc Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Sun, 24 Apr 2022 12:48:48 -0500 Subject: [PATCH 108/133] Test to ensure stdlib `split` is still accessible --- Tests/RegexTests/AlgorithmsTests.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Tests/RegexTests/AlgorithmsTests.swift b/Tests/RegexTests/AlgorithmsTests.swift index c42ff175f..965e2c42e 100644 --- a/Tests/RegexTests/AlgorithmsTests.swift +++ b/Tests/RegexTests/AlgorithmsTests.swift @@ -135,6 +135,12 @@ class AlgorithmTests: XCTestCase { expectSplit("a", "a", ["", ""]) expectSplit("a____a____a", "_+", ["a", "a", "a"]) expectSplit("____a____a____a____", "_+", ["", "a", "a", "a", ""]) + + // Test that original `split` functions are still accessible + let splitRef = "abcd".split + XCTAssert(type(of: splitRef) == ((Character, Int, Bool) -> [Substring]).self) + let splitParamsRef = "abcd".split(separator:maxSplits:omittingEmptySubsequences:) + XCTAssert(type(of: splitParamsRef) == ((Character, Int, Bool) -> [Substring]).self) } func testSplitPermutations() throws { From 433740b885f5a8012c89ee5d6cc08b92e4ba7ad7 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Mon, 25 Apr 2022 10:06:19 -0600 Subject: [PATCH 109/133] Fix stale links --- Documentation/Evolution/RegexSyntaxRunTimeConstruction.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md index 5c9fa6c59..bee7bbf03 100644 --- a/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md +++ b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md @@ -12,7 +12,7 @@ A regex declares a string processing algorithm using syntax familiar across a variety of languages and tools throughout programming history. We propose the ability to create a regex at run time from a string containing regex syntax (detailed here), API for accessing the match and captures, and a means to convert between an existential capture representation and concrete types. -The overall story is laid out in [Regex Type and Overview][overview] and each individual component is tracked in [Pitch and Proposal Status](https://github.com/apple/swift-experimental-string-processing/issues/107). +The overall story is laid out in [SE-0350 Regex Type and Overview][overview] and each individual component is tracked in [Pitch and Proposal Status][pitches]. ## Motivation @@ -341,7 +341,7 @@ BuiltinCharClass -> '.' | '\C' | '\d' | '\D' | '\h' | '\H' | '\N' | '\O' | '\R' - `\W`: Non-word character. - `\X`: Any extended grapheme cluster. -Precise definitions of character classes is discussed in [Character Classes for String Processing](https://forums.swift.org/t/pitch-character-classes-for-string-processing/52920). +Precise definitions of character classes is discussed in [Unicode for String Processing][pitches]. #### Unicode scalars @@ -1009,8 +1009,8 @@ This proposal regards _syntactic_ support, and does not necessarily mean that ev [unicode-scripts]: https://www.unicode.org/reports/tr24/#Script [unicode-script-extensions]: https://www.unicode.org/reports/tr24/#Script_Extensions [balancing-groups]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/grouping-constructs-in-regular-expressions#balancing-group-definitions -[overview]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexTypeOverview.md -[pitches]: https://github.com/apple/swift-experimental-string-processing/issues/107 +[overview]: https://github.com/apple/swift-evolution/blob/main/proposals/0350-regex-type-overview.md +[pitches]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/ProposalOverview.md From 8dce8c2993ba4bc0181cda05ae0c25b46a06d01e Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Mon, 25 Apr 2022 10:12:25 -0600 Subject: [PATCH 110/133] Mention API naming consistency (#341) * Mention API naming consistency --- .../Evolution/StringProcessingAlgorithms.md | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Documentation/Evolution/StringProcessingAlgorithms.md b/Documentation/Evolution/StringProcessingAlgorithms.md index 0539d46ca..cee6104e2 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -835,6 +835,46 @@ extension RangeReplaceableCollection where Element: Equatable { Most of the proposed algorithms are necessarily on `Collection` due to the use of indices or mutation. `Sequence` does not support multi-pass iteration, so even `trimPrefix` would problematic on `Sequence` because it needs to look 1 `Element` ahead to know when to stop trimming. +### Cross-proposal API naming consistency + +The regex work is broken down into 6 proposals based on technical domain, which is advantageous for deeper technical discussions and makes reviewing the large body of work manageable. The disadvantage of this approach is that relatively-shallow cross-cutting concerns, such as API naming consistency, are harder to evaluate until we've built up intuition from multiple proposals. + +We've seen the [Regex type and overview](https://github.com/apple/swift-evolution/blob/main/proposals/0350-regex-type-overview.md), the [Regex builder DSL](https://github.com/apple/swift-evolution/blob/main/proposals/0351-regex-builder.md), and here we present lots of ways to use regex. Now's a good time to go over API naming consistency. + +(The other proposal with a significant amount of API is [Unicode for String Processing](https://forums.swift.org/t/pitch-unicode-for-string-processing/56907), which is in the pitch phase. It is a technical niche and less impactful on these naming discussions. We'll still want to design those names for consistency, of course.) + + +```swift +protocol RegexComponent { + associatedtype RegexOutput +} +``` + +The associatedtype name is "RegexOutput" to help libraries conform their parsers to this protocol (e.g. via `CustomConsumingRegexComponent`). Regex's capture representation is regexy: it has the overall matched portion as the first capture and the regex builders know how to combine these kinds of capture lists together. This could be different than how e.g. a parser combinator library's output types might be represented. Thus, we chose a more specific name to avoid any potential conflicts. + +The name "RegexComponent" accentuates that any conformer can be used as part of a larger regex, while it de-emphasizes that `Regex` instances themselves can be used directly. We propose methods that are generic over `RegexComponent` and developers will be considering whether they should make their functions that otherwise take a `Regex` also be generic over `RegexComponent`. + +It's possible there might be some initial confusion around the word "component", i.e. a developer may have a regex and not be sure how to make it into a component or how to get the component out. The word "component" carries a lot of value in the context of the regex DSL. An alternative name might be `RegexProtocol`, which implies that a Regex can be used at the site and would be clearly the way to make a function taking a concrete `Regex` generic. But, it's otherwise a naming workaround that doesn't carry the additional regex builder connotations. + +The protocol requirement is `var regex: Regex`, i.e. any type that can produce a regex or hook into the engine's customization hooks (this is what `consuming` does) can be used as a component of the DSL and with these generic API. An alternative name could be "CustomRegexConvertible", but we don't feel that communicates component composability very well, nor is it particularly enlightening when encountering these generic API. + +Another alternative is to have a second protocol just for generic API. But without a compelling semantic distinction or practical utility, we'd prefer to avoid adding protocols just for names. If a clearly superior name exists, we should just choose that. + + +```swift +protocol CustomConsumingRegexComponent { + func consuming(...) +} +``` + +This is not a normal developer-facing protocol or concept; it's an advanced library-extensibility feature. Explicit, descriptive, and careful names are more important than concise names. The "custom" implies that we're not just vending a regex directly ourselves, we're instead customizing behavior by hooking into the run-time engine directly. + +Older versions of the pitch had `func match(...) -> (String.Index, T)?` as the protocol requirement. As [Regex type and overview](https://github.com/apple/swift-evolution/blob/main/proposals/0350-regex-type-overview.md) went through review, naming convention settled on using the word "match" as a noun and in context with operations that produce a `Match` instance. Since this is the engine's customization hook, it produces the value and position to resume execution from directly, and hence different terminology is apt and avoids confusion or future ambiguities. "Consuming" is the nomenclature we're going with for something that chews off the front of its input in order to produces a value. + +This protocol customizes the basic consume-from-the-front functionality. A protocol for customizing search is future work and involves accommodating different kinds of state and ways that a searcher may wish to speed up subsequent searches. Alternative names for the protocol include `CustomRegexComponent`, `CustomConsumingRegex`, etc., but we don't feel brevity is the key consideration here. + + + ## Future directions ### Backward algorithms From 1fd5115d7fac901f892f0cae9fd3891682ce9ea9 Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Sat, 23 Apr 2022 16:43:07 -0700 Subject: [PATCH 111/133] Generic `~=` operator Make `~=` generic over `RegexComponent` so that one can use builder components, e.g. `OneOrMore(...)`, or custom-consuming regex components as patterns. --- Sources/_StringProcessing/Regex/Core.swift | 7 +++ Sources/_StringProcessing/Regex/Match.swift | 20 ++----- Tests/RegexBuilderTests/AlgorithmsTests.swift | 57 +++++++++++++++++++ 3 files changed, 70 insertions(+), 14 deletions(-) diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index d77784df4..36d62f674 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -61,6 +61,13 @@ public struct Regex: RegexComponent { } } +@available(SwiftStdlib 5.7, *) +extension Regex { + public init(quoting string: String) { + self.init(node: .quotedLiteral(string)) + } +} + @available(SwiftStdlib 5.7, *) extension Regex { /// A program representation that caches any lowered representation for diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 39ff7ece9..45df7aeaa 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -180,20 +180,12 @@ extension BidirectionalCollection where SubSequence == Substring { } @available(SwiftStdlib 5.7, *) -extension Regex { - public init(quoting string: String) { - self.init(node: .quotedLiteral(string)) +extension RegexComponent { + public static func ~=(regex: Self, input: String) -> Bool { + input.wholeMatch(of: regex) != nil } -} -@available(SwiftStdlib 5.7, *) -public func ~=(regex: Regex, input: String) -> Bool { - guard let _ = try? regex.wholeMatch(in: input) else { return false } - return true -} - -@available(SwiftStdlib 5.7, *) -public func ~=(regex: Regex, input: Substring) -> Bool { - guard let _ = try? regex.wholeMatch(in: input) else { return false } - return true + public static func ~=(regex: Self, input: Substring) -> Bool { + input.wholeMatch(of: regex) != nil + } } diff --git a/Tests/RegexBuilderTests/AlgorithmsTests.swift b/Tests/RegexBuilderTests/AlgorithmsTests.swift index 5a7a69fac..97fccde01 100644 --- a/Tests/RegexBuilderTests/AlgorithmsTests.swift +++ b/Tests/RegexBuilderTests/AlgorithmsTests.swift @@ -104,4 +104,61 @@ class RegexConsumerTests: XCTestCase { result: "9+16, 3, 10, 99+1") ) } + + func testSwitches() { + // Failure cases + do { + switch "abcde" { + case Regex { + "a" + ZeroOrMore(.any) + "f" + }: + XCTFail() + + case "abc": + XCTFail() + + case Regex { + "a" + "b" + "c" + }: + XCTFail() + + default: + break + } + } + // Success cases + do { + let input = "abcde" + + switch input { + case Regex { + "a" + ZeroOrMore(.any) + "e" + }: + break + + default: + XCTFail() + } + + guard case Regex({ + "a" + ZeroOrMore(.any) + "e" + }) = input else { + XCTFail() + return + } + + guard case OneOrMore(.word) = input else { + XCTFail() + return + } + } + } } From 5af1427872057dd7928ad133a7238809e8ba5471 Mon Sep 17 00:00:00 2001 From: Tina Liu <49205802+itingliu@users.noreply.github.com> Date: Mon, 25 Apr 2022 15:36:07 -0700 Subject: [PATCH 112/133] Add `@RegexComponentBuilder` overloads for collection algorithms (#342) * Add `@RegexComponentBuilder` overloads for collection algorithms - Add overloads per string processing proposal - Update doc comments - Add tests that uses the builder - Rename `Match.swift` to `Algorithms.swift` as it contains more than match functions now * Update the proposal as well --- .../Evolution/StringProcessingAlgorithms.md | 230 +++++++----- Sources/RegexBuilder/Algorithms.swift | 310 ++++++++++++++++ Sources/RegexBuilder/Match.swift | 45 --- Tests/RegexBuilderTests/AlgorithmsTests.swift | 338 +++++++++++++++++- 4 files changed, 784 insertions(+), 139 deletions(-) create mode 100644 Sources/RegexBuilder/Algorithms.swift delete mode 100644 Sources/RegexBuilder/Match.swift diff --git a/Documentation/Evolution/StringProcessingAlgorithms.md b/Documentation/Evolution/StringProcessingAlgorithms.md index cee6104e2..eee05e3a7 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -246,12 +246,13 @@ extension BidirectionalCollection where SubSequence == Substring { /// `false`. public func contains(_ regex: some RegexComponent) -> Bool - /// Returns a Boolean value indicating whether the collection contains the - /// given regex. - /// - Parameter content: A closure to produce a `RegexComponent` to search for - /// within this collection. - /// - Returns: `true` if the regex was found in the collection, otherwise - /// `false`. + /// Returns a Boolean value indicating whether this collection contains a + /// match for the regex, where the regex is created by the given closure. + /// + /// - Parameter content: A closure that returns a regex to search for within + /// this collection. + /// - Returns: `true` if the regex returned by `content` matched anywhere in + /// this collection, otherwise `false`. public func contains( @RegexComponentBuilder _ content: () -> some RegexComponent ) -> Bool @@ -269,11 +270,13 @@ extension BidirectionalCollection where SubSequence == Substring { /// beginning of `regex`; otherwise, `false`. public func starts(with regex: some RegexComponent) -> Bool - /// Returns a Boolean value indicating whether the initial elements of the - /// sequence are the same as the elements in the specified regex. - /// - Parameter content: A closure to produce a `RegexComponent` to compare. - /// - Returns: `true` if the initial elements of the sequence matches the - /// beginning of `regex`; otherwise, `false`. + /// Returns a Boolean value indicating whether the initial elements of this + /// collection are a match for the regex created by the given closure. + /// + /// - Parameter content: A closure that returns a regex to match at + /// the beginning of this collection. + /// - Returns: `true` if the initial elements of this collection match + /// regex returned by `content`; otherwise, `false`. public func starts( @RegexComponentBuilder with content: () -> some RegexComponent ) -> Bool @@ -344,11 +347,16 @@ extension BidirectionalCollection where SubSequence == Substring { /// that does not match `prefix` from the start. public func trimmingPrefix(_ regex: some RegexComponent) -> SubSequence - /// Returns a new collection of the same type by removing `prefix` from the - /// start. - /// - Parameter _content A closure to produce a `RegexComponent` to be removed. - /// - Returns: A collection containing the elements that does not match - /// `prefix` from the start. + /// Returns a subsequence of this collection by removing the elements + /// matching the regex from the start, where the regex is created by + /// the given closure. + /// + /// - Parameter content: A closure that returns the regex to search for at + /// the start of this collection. + /// - Returns: A collection containing the elements after those that match + /// the regex returned by `content`. If the regex does not match at + /// the start of the collection, the entire contents of this collection + /// are returned. public func trimmingPrefix( @RegexComponentBuilder _ content: () -> some RegexComponent ) -> SubSequence @@ -361,8 +369,12 @@ extension RangeReplaceableCollection /// - Parameter regex: The regex to remove from this collection. public mutating func trimPrefix(_ regex: some RegexComponent) - /// Removes the initial elements that matches the given regex. - /// - Parameter content: A closure to produce a `RegexComponent` to be removed. + /// Removes the initial elements matching the regex from the start of + /// this collection, if the initial elements match, using the given closure + /// to create the regex. + /// + /// - Parameter content: A closure that returns the regex to search for + /// at the start of this collection. public mutating func trimPrefix( @RegexComponentBuilder _ content: () -> some RegexComponent ) @@ -400,12 +412,13 @@ extension BidirectionalCollection where SubSequence == Substring { /// Returns `nil` if `regex` is not found. public func firstRange(of regex: some RegexComponent) -> Range? - /// Finds and returns the range of the first occurrence of a given regex - /// within the collection. - /// - Parameter content: A closure to produce a `RegexComponent` to search for - /// within this collection. - /// - Returns: A range in the collection of the first occurrence of regex. - /// Returns `nil` if not found. + /// Returns the range of the first match for the regex within this collection, + /// where the regex is created by the given closure. + /// + /// - Parameter content: A closure that returns a regex to search for. + /// - Returns: A range in the collection of the first occurrence of the first + /// match of if the regex returned by `content`. Returns `nil` if no match + /// for the regex is found. public func firstRange( @RegexComponentBuilder of content: () -> some RegexComponent ) -> Range? @@ -433,12 +446,13 @@ extension BidirectionalCollection where SubSequence == Substring { /// `regex`. Returns an empty collection if `regex` is not found. public func ranges(of regex: some RegexComponent) -> some Collection> - /// Finds and returns the ranges of the all occurrences of a given sequence - /// within the collection. - /// - Parameter content: A closure to produce a `RegexComponent` to search for - /// within this collection. - /// - Returns: A collection or ranges in the receiver of all occurrences of - /// regex. Returns an empty collection if not found. + /// Returns the ranges of the all non-overlapping matches for the regex + /// within this collection, where the regex is created by the given closure. + /// + /// - Parameter content: A closure that returns a regex to search for. + /// - Returns: A collection of ranges of all matches for the regex returned by + /// `content`. Returns an empty collection if no match for the regex + /// is found. public func ranges( @RegexComponentBuilder of content: () -> some RegexComponent ) -> some Collection> @@ -455,10 +469,12 @@ extension BidirectionalCollection where SubSequence == Substring { /// there isn't a match. public func firstMatch(of regex: R) -> Regex.Match? - /// Returns the first match of the specified regex within the collection. - /// - Parameter content: A closure to produce a `RegexComponent` to search for. - /// - Returns: The first match of regex in the collection, or `nil` if - /// there isn't a match. + /// Returns the first match for the regex within this collection, where + /// the regex is created by the given closure. + /// + /// - Parameter content: A closure that returns the regex to search for. + /// - Returns: The first match for the regex created by `content` in this + /// collection, or `nil` if no match is found. public func firstMatch( @RegexComponentBuilder of content: () -> R ) -> Regex.Match? @@ -468,8 +484,10 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: The match if there is one, or `nil` if none. public func wholeMatch(of regex: R) -> Regex.Match? - /// Match a regex in its entirety. - /// - Parameter content: A closure to produce a `RegexComponent` to match against. + /// Matches a regex in its entirety, where the regex is created by + /// the given closure. + /// + /// - Parameter content: A closure that returns a regex to match against. /// - Returns: The match if there is one, or `nil` if none. public func wholeMatch( @RegexComponentBuilder of content: () -> R @@ -480,8 +498,10 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: The match if there is one, or `nil` if none. public func prefixMatch(of regex: R) -> Regex.Match? - /// Match part of the regex, starting at the beginning. - /// - Parameter content: A closure to produce a `RegexComponent` to match against. + /// Matches part of the regex, starting at the beginning, where the regex + /// is created by the given closure. + /// + /// - Parameter content: A closure that returns a regex to match against. /// - Returns: The match if there is one, or `nil` if none. public func prefixMatch( @RegexComponentBuilder of content: () -> R @@ -498,9 +518,12 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: A collection of matches of `regex`. public func matches(of regex: R) -> some Collection.Match> - /// Returns a collection containing all matches of the specified regex. - /// - Parameter content: A closure to produce a `RegexComponent` to search for. - /// - Returns: A collection of matches of `regex`. + /// Returns a collection containing all non-overlapping matches of + /// the regex, created by the given closure. + /// + /// - Parameter content: A closure that returns the regex to search for. + /// - Returns: A collection of matches for the regex returned by `content`. + /// If no matches are found, the returned collection is empty. public func matches( @RegexComponentBuilder of content: () -> R ) -> some Collection.Match> @@ -574,16 +597,20 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: Int = .max ) -> Self where Replacement.Element == Element - /// Returns a new collection in which all occurrences of a sequence matching - /// the given regex are replaced by another collection. + /// Returns a new collection in which all matches for the regex + /// are replaced, using the given closure to create the regex. + /// /// - Parameters: - /// - replacement: The new elements to add to the collection. - /// - subrange: The range in the collection in which to search for `regex`. - /// - maxReplacements: A number specifying how many occurrences of the - /// sequence matching `regex` to replace. Default is `Int.max`. - /// - content: A closure to produce a `RegexComponent` to replace. - /// - Returns: A new collection in which all occurrences of subsequence - /// matching `regex` in `subrange` are replaced by `replacement`. + /// - replacement: The new elements to add to the collection in place of + /// each match for the regex, using `content` to create the regex. + /// - subrange: The range in the collection in which to search for + /// the regex. + /// - maxReplacements: A number specifying how many occurrences of + /// the regex to replace. + /// - content: A closure that returns the collection to search for + /// and replace. + /// - Returns: A new collection in which all matches for regex in `subrange` + /// are replaced by `replacement`, using `content` to create the regex. public func replacing( with replacement: Replacement, subrange: Range, @@ -606,15 +633,18 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: Int = .max ) -> Self where Replacement.Element == Element - /// Returns a new collection in which all occurrences of a sequence matching - /// the given regex are replaced by another collection. + /// Returns a new collection in which all matches for the regex + /// are replaced, using the given closure to create the regex. + /// /// - Parameters: - /// - replacement: The new elements to add to the collection. - /// - maxReplacements: A number specifying how many occurrences of the - /// sequence matching `regex` to replace. Default is `Int.max`. - /// - content: A closure to produce a `RegexComponent` to replace. - /// - Returns: A new collection in which all occurrences of subsequence - /// matching `regex` are replaced by `replacement`. + /// - replacement: The new elements to add to the collection in place of + /// each match for the regex, using `content` to create the regex. + /// - maxReplacements: A number specifying how many occurrences of regex + /// to replace. + /// - content: A closure that returns the collection to search for + /// and replace. + /// - Returns: A new collection in which all matches for regex in `subrange` + /// are replaced by `replacement`, using `content` to create the regex. public func replacing( with replacement: Replacement, maxReplacements: Int = .max, @@ -634,18 +664,21 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: Int = .max ) where Replacement.Element == Element - /// Replaces all occurrences of the sequence matching the given regex with - /// a given collection. + /// Replaces all matches for the regex in this collection, using the given + /// closure to create the regex. + /// /// - Parameters: - /// - replacement: The new elements to add to the collection. - /// - maxReplacements: A number specifying how many occurrences of the - /// sequence matching `regex` to replace. Default is `Int.max`. - /// - content: A closure to produce a `RegexComponent` to replace. + /// - replacement: The new elements to add to the collection in place of + /// each match for the regex, using `content` to create the regex. + /// - maxReplacements: A number specifying how many occurrences of + /// the regex to replace. + /// - content: A closure that returns the collection to search for + /// and replace. public mutating func replace( with replacement: Replacement, maxReplacements: Int = .max, @RegexComponentBuilder content: () -> some RegexComponent - ) -> Self where Replacement.Element == Element + ) where Replacement.Element == Element /// Returns a new collection in which all occurrences of a sequence matching /// the given regex are replaced by another regex match. @@ -664,18 +697,23 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: Int = .max, with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element - - /// Returns a new collection in which all occurrences of a sequence matching - /// the given regex are replaced by another regex match. + + /// Returns a new collection in which all matches for the regex + /// are replaced, using the given closures to create the replacement + /// and the regex. + /// /// - Parameters: - /// - subrange: The range in the collection in which to search for `regex`. - /// - maxReplacements: A number specifying how many occurrences of the - /// sequence matching `regex` to replace. Default is `Int.max`. - /// - content: A closure to produce a `RegexComponent` to replace. + /// - subrange: The range in the collection in which to search for the + /// regex, using `content` to create the regex. + /// - maxReplacements: A number specifying how many occurrences of + /// the regex to replace. + /// - content: A closure that returns the collection to search for + /// and replace. /// - replacement: A closure that receives the full match information, - /// including captures, and returns a replacement collection. - /// - Returns: A new collection in which all occurrences of subsequence - /// matching `regex` are replaced by `replacement`. + /// including captures, and returns a replacement collection. + /// - Returns: A new collection in which all matches for regex in `subrange` + /// are replaced by the result of calling `replacement`, where regex + /// is the result of calling `content`. public func replacing( subrange: Range, maxReplacements: Int = .max, @@ -699,16 +737,20 @@ extension RangeReplaceableCollection where SubSequence == Substring { with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element - /// Returns a new collection in which all occurrences of a sequence matching - /// the given regex are replaced by another collection. + /// Returns a new collection in which all matches for the regex + /// are replaced, using the given closures to create the replacement + /// and the regex. + /// /// - Parameters: - /// - maxReplacements: A number specifying how many occurrences of the - /// sequence matching `regex` to replace. Default is `Int.max`. - /// - content: A closure to produce a `RegexComponent` to replace. + /// - maxReplacements: A number specifying how many occurrences of + /// the regex to replace, using `content` to create the regex. + /// - content: A closure that returns the collection to search for + /// and replace. /// - replacement: A closure that receives the full match information, /// including captures, and returns a replacement collection. - /// - Returns: A new collection in which all occurrences of subsequence - /// matching `regex` are replaced by `replacement`. + /// - Returns: A new collection in which all matches for regex in `subrange` + /// are replaced by the result of calling `replacement`, where regex is + /// the result of calling `content`. public func replacing( maxReplacements: Int = .max, @RegexComponentBuilder content: () -> R, @@ -728,15 +770,17 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: Int = .max, with replacement: (Regex.Match) throws -> Replacement ) rethrows where Replacement.Element == Element - - /// Replaces all occurrences of the sequence matching the given regex with - /// a given collection. + + /// Replaces all matches for the regex in this collection, using the + /// given closures to create the replacement and the regex. + /// /// - Parameters: - /// - maxReplacements: A number specifying how many occurrences of the - /// sequence matching `regex` to replace. Default is `Int.max`. - /// - content: A closure to produce a `RegexComponent` to replace. + /// - maxReplacements: A number specifying how many occurrences of + /// the regex to replace, using `content` to create the regex. + /// - content: A closure that returns the collection to search for + /// and replace. /// - replacement: A closure that receives the full match information, - /// including captures, and returns a replacement collection. + /// including captures, and returns a replacement collection. public mutating func replace( maxReplacements: Int = .max, @RegexComponentBuilder content: () -> R, @@ -791,16 +835,16 @@ extension BidirectionalCollection where SubSequence == Substring { ) -> some Collection /// Returns the longest possible subsequences of the collection, in order, - /// around subsequence that match the given separator regex. + /// around subsequence that match the regex created by the given closure. /// /// - Parameters: - /// - maxSplits: The maximum number of times to split the collection, + /// - maxSplits: The maximum number of times to split the collection, /// or one less than the number of subsequences to return. - /// - omittingEmptySubsequences: If `false`, an empty subsequence is + /// - omittingEmptySubsequences: If `false`, an empty subsequence is /// returned in the result for each consecutive pair of matches /// and for each match at the start or end of the collection. If /// `true`, only nonempty subsequences are returned. - /// - separator: A closure to produce a `RegexComponent` to be split upon. + /// - separator: A closure that returns a regex to be split upon. /// - Returns: A collection of substrings, split from this collection's /// elements. public func split( diff --git a/Sources/RegexBuilder/Algorithms.swift b/Sources/RegexBuilder/Algorithms.swift new file mode 100644 index 000000000..f206ee768 --- /dev/null +++ b/Sources/RegexBuilder/Algorithms.swift @@ -0,0 +1,310 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +import _StringProcessing + +extension BidirectionalCollection where SubSequence == Substring { + /// Matches a regex in its entirety, where the regex is created by + /// the given closure. + /// + /// - Parameter content: A closure that returns a regex to match against. + /// - Returns: The match if there is one, or `nil` if none. + @available(SwiftStdlib 5.7, *) + public func wholeMatch( + @RegexComponentBuilder of content: () -> R + ) -> Regex.Match? { + wholeMatch(of: content()) + } + + /// Matches part of the regex, starting at the beginning, where the regex + /// is created by the given closure. + /// + /// - Parameter content: A closure that returns a regex to match against. + /// - Returns: The match if there is one, or `nil` if none. + @available(SwiftStdlib 5.7, *) + public func prefixMatch( + @RegexComponentBuilder of content: () -> R + ) -> Regex.Match? { + prefixMatch(of: content()) + } + + /// Returns a Boolean value indicating whether this collection contains a + /// match for the regex, where the regex is created by the given closure. + /// + /// - Parameter content: A closure that returns a regex to search for within + /// this collection. + /// - Returns: `true` if the regex returned by `content` matched anywhere in + /// this collection, otherwise `false`. + @available(SwiftStdlib 5.7, *) + public func contains( + @RegexComponentBuilder _ content: () -> R + ) -> Bool { + contains(content()) + } + + /// Returns the range of the first match for the regex within this collection, + /// where the regex is created by the given closure. + /// + /// - Parameter content: A closure that returns a regex to search for. + /// - Returns: A range in the collection of the first occurrence of the first + /// match of if the regex returned by `content`. Returns `nil` if no match + /// for the regex is found. + @available(SwiftStdlib 5.7, *) + public func firstRange( + @RegexComponentBuilder of content: () -> R + ) -> Range? { + firstRange(of: content()) + } + + // FIXME: Return `some Collection>` for SE-0346 + /// Returns the ranges of the all non-overlapping matches for the regex + /// within this collection, where the regex is created by the given closure. + /// + /// - Parameter content: A closure that returns a regex to search for. + /// - Returns: A collection of ranges of all matches for the regex returned by + /// `content`. Returns an empty collection if no match for the regex + /// is found. + @available(SwiftStdlib 5.7, *) + public func ranges( + @RegexComponentBuilder of content: () -> R + ) -> [Range] { + ranges(of: content()) + } + + // FIXME: Return `some Collection` for SE-0346 + /// Returns the longest possible subsequences of the collection, in order, + /// around subsequence that match the regex created by the given closure. + /// + /// - Parameters: + /// - maxSplits: The maximum number of times to split the collection, + /// or one less than the number of subsequences to return. + /// - omittingEmptySubsequences: If `false`, an empty subsequence is + /// returned in the result for each consecutive pair of matches + /// and for each match at the start or end of the collection. If + /// `true`, only nonempty subsequences are returned. + /// - separator: A closure that returns a regex to be split upon. + /// - Returns: A collection of substrings, split from this collection's + /// elements. + @available(SwiftStdlib 5.7, *) + public func split( + maxSplits: Int = Int.max, + omittingEmptySubsequences: Bool = true, + @RegexComponentBuilder separator: () -> some RegexComponent + ) -> [SubSequence] { + split(separator: separator(), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) + } + + /// Returns a Boolean value indicating whether the initial elements of this + /// collection are a match for the regex created by the given closure. + /// + /// - Parameter content: A closure that returns a regex to match at + /// the beginning of this collection. + /// - Returns: `true` if the initial elements of this collection match + /// regex returned by `content`; otherwise, `false`. + @available(SwiftStdlib 5.7, *) + public func starts( + @RegexComponentBuilder with content: () -> R + ) -> Bool { + starts(with: content()) + } + + /// Returns a subsequence of this collection by removing the elements + /// matching the regex from the start, where the regex is created by + /// the given closure. + /// + /// - Parameter content: A closure that returns the regex to search for at + /// the start of this collection. + /// - Returns: A collection containing the elements after those that match + /// the regex returned by `content`. If the regex does not match at + /// the start of the collection, the entire contents of this collection + /// are returned. + @available(SwiftStdlib 5.7, *) + public func trimmingPrefix( + @RegexComponentBuilder _ content: () -> R + ) -> SubSequence { + trimmingPrefix(content()) + } + + /// Returns the first match for the regex within this collection, where + /// the regex is created by the given closure. + /// + /// - Parameter content: A closure that returns the regex to search for. + /// - Returns: The first match for the regex created by `content` in this + /// collection, or `nil` if no match is found. + @available(SwiftStdlib 5.7, *) + public func firstMatch( + @RegexComponentBuilder of content: () -> R + ) -> Regex.Match? { + firstMatch(of: content()) + } + + // FIXME: Return `some Collection.Match> for SE-0346 + /// Returns a collection containing all non-overlapping matches of + /// the regex, created by the given closure. + /// + /// - Parameter content: A closure that returns the regex to search for. + /// - Returns: A collection of matches for the regex returned by `content`. + /// If no matches are found, the returned collection is empty. + @available(SwiftStdlib 5.7, *) + public func matches( + @RegexComponentBuilder of content: () -> R + ) -> [Regex.Match] { + matches(of: content()) + } +} + +extension RangeReplaceableCollection +where Self: BidirectionalCollection, SubSequence == Substring { + /// Removes the initial elements matching the regex from the start of + /// this collection, if the initial elements match, using the given closure + /// to create the regex. + /// + /// - Parameter content: A closure that returns the regex to search for + /// at the start of this collection. + @available(SwiftStdlib 5.7, *) + public mutating func trimPrefix( + @RegexComponentBuilder _ content: () -> R + ) { + trimPrefix(content()) + } + + /// Returns a new collection in which all matches for the regex + /// are replaced, using the given closure to create the regex. + /// + /// - Parameters: + /// - replacement: The new elements to add to the collection in place of + /// each match for the regex, using `content` to create the regex. + /// - subrange: The range in the collection in which to search for + /// the regex. + /// - maxReplacements: A number specifying how many occurrences of + /// the regex to replace. + /// - content: A closure that returns the collection to search for + /// and replace. + /// - Returns: A new collection in which all matches for regex in `subrange` + /// are replaced by `replacement`, using `content` to create the regex. + @available(SwiftStdlib 5.7, *) + public func replacing( + with replacement: Replacement, + subrange: Range, + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> some RegexComponent + ) -> Self where Replacement.Element == Element { + replacing(content(), with: replacement, subrange: subrange, maxReplacements: maxReplacements) + } + + /// Returns a new collection in which all matches for the regex + /// are replaced, using the given closure to create the regex. + /// + /// - Parameters: + /// - replacement: The new elements to add to the collection in place of + /// each match for the regex, using `content` to create the regex. + /// - maxReplacements: A number specifying how many occurrences of regex + /// to replace. + /// - content: A closure that returns the collection to search for + /// and replace. + /// - Returns: A new collection in which all matches for regex in `subrange` + /// are replaced by `replacement`, using `content` to create the regex. + @available(SwiftStdlib 5.7, *) + public func replacing( + with replacement: Replacement, + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> some RegexComponent + ) -> Self where Replacement.Element == Element { + replacing(content(), with: replacement, maxReplacements: maxReplacements) + } + + /// Replaces all matches for the regex in this collection, using the given + /// closure to create the regex. + /// + /// - Parameters: + /// - replacement: The new elements to add to the collection in place of + /// each match for the regex, using `content` to create the regex. + /// - maxReplacements: A number specifying how many occurrences of + /// the regex to replace. + /// - content: A closure that returns the collection to search for + /// and replace. + @available(SwiftStdlib 5.7, *) + public mutating func replace( + with replacement: Replacement, + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> some RegexComponent + ) where Replacement.Element == Element { + replace(content(), with: replacement, maxReplacements: maxReplacements) + } + + /// Returns a new collection in which all matches for the regex + /// are replaced, using the given closures to create the replacement + /// and the regex. + /// + /// - Parameters: + /// - subrange: The range in the collection in which to search for the + /// regex, using `content` to create the regex. + /// - maxReplacements: A number specifying how many occurrences of + /// the regex to replace. + /// - content: A closure that returns the collection to search for + /// and replace. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. + /// - Returns: A new collection in which all matches for regex in `subrange` + /// are replaced by the result of calling `replacement`, where regex + /// is the result of calling `content`. + @available(SwiftStdlib 5.7, *) + public func replacing( + subrange: Range, + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> R, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows -> Self where Replacement.Element == Element { + try replacing(content(), subrange: subrange, maxReplacements: maxReplacements, with: replacement) + } + + /// Returns a new collection in which all matches for the regex + /// are replaced, using the given closures to create the replacement + /// and the regex. + /// + /// - Parameters: + /// - maxReplacements: A number specifying how many occurrences of + /// the regex to replace, using `content` to create the regex. + /// - content: A closure that returns the collection to search for + /// and replace. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. + /// - Returns: A new collection in which all matches for regex in `subrange` + /// are replaced by the result of calling `replacement`, where regex is + /// the result of calling `content`. + @available(SwiftStdlib 5.7, *) + public func replacing( + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> R, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows -> Self where Replacement.Element == Element { + try replacing(content(), maxReplacements: maxReplacements, with: replacement) + } + + /// Replaces all matches for the regex in this collection, using the + /// given closures to create the replacement and the regex. + /// + /// - Parameters: + /// - maxReplacements: A number specifying how many occurrences of + /// the regex to replace, using `content` to create the regex. + /// - content: A closure that returns the collection to search for + /// and replace. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. + @available(SwiftStdlib 5.7, *) + public mutating func replace( + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> R, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows where Replacement.Element == Element { + try replace(content(), maxReplacements: maxReplacements, with: replacement) + } +} diff --git a/Sources/RegexBuilder/Match.swift b/Sources/RegexBuilder/Match.swift deleted file mode 100644 index 78a466a18..000000000 --- a/Sources/RegexBuilder/Match.swift +++ /dev/null @@ -1,45 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// -//===----------------------------------------------------------------------===// - -import _StringProcessing - -@available(SwiftStdlib 5.7, *) -extension String { - @available(SwiftStdlib 5.7, *) - public func wholeMatch( - @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? { - wholeMatch(of: content()) - } - - @available(SwiftStdlib 5.7, *) - public func prefixMatch( - @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? { - prefixMatch(of: content()) - } -} - -extension Substring { - @available(SwiftStdlib 5.7, *) - public func wholeMatch( - @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? { - wholeMatch(of: content()) - } - - @available(SwiftStdlib 5.7, *) - public func prefixMatch( - @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? { - prefixMatch(of: content()) - } -} diff --git a/Tests/RegexBuilderTests/AlgorithmsTests.swift b/Tests/RegexBuilderTests/AlgorithmsTests.swift index 5a7a69fac..0a2e6bc21 100644 --- a/Tests/RegexBuilderTests/AlgorithmsTests.swift +++ b/Tests/RegexBuilderTests/AlgorithmsTests.swift @@ -11,7 +11,7 @@ import XCTest import _StringProcessing -@testable import RegexBuilder +import RegexBuilder @available(SwiftStdlib 5.7, *) class RegexConsumerTests: XCTestCase { @@ -105,3 +105,339 @@ class RegexConsumerTests: XCTestCase { ) } } + +class AlgorithmsResultBuilderTests: XCTestCase { + enum MatchAlgo { + case whole + case first + case prefix + } + + enum EquatableAlgo { + case starts + case contains + case trimmingPrefix + } + + func expectMatch( + _ algo: MatchAlgo, + _ tests: (input: String, expectedCaptures: MatchType?)..., + matchType: MatchType.Type, + equivalence: (MatchType, MatchType) -> Bool, + file: StaticString = #file, + line: UInt = #line, + @RegexComponentBuilder _ content: () -> R + ) throws { + for (input, expectedCaptures) in tests { + var actual: Regex.Match? + switch algo { + case .whole: + actual = input.wholeMatch(of: content) + case .first: + actual = input.firstMatch(of: content) + case .prefix: + actual = input.prefixMatch(of: content) + } + if let expectedCaptures = expectedCaptures { + let match = try XCTUnwrap(actual, file: file, line: line) + let captures = try XCTUnwrap(match.output as? MatchType, file: file, line: line) + XCTAssertTrue(equivalence(captures, expectedCaptures), file: file, line: line) + } else { + XCTAssertNil(actual, file: file, line: line) + } + } + } + + func expectEqual( + _ algo: EquatableAlgo, + _ tests: (input: String, expected: Expected)..., + file: StaticString = #file, + line: UInt = #line, + @RegexComponentBuilder _ content: () -> R + ) throws { + for (input, expected) in tests { + var actual: Expected + switch algo { + case .contains: + actual = input.contains(content) as! Expected + case .starts: + actual = input.starts(with: content) as! Expected + case .trimmingPrefix: + actual = input.trimmingPrefix(content) as! Expected + } + XCTAssertEqual(actual, expected) + } + } + + func testMatches() throws { + let int = Capture(OneOrMore(.digit)) { Int($0)! } + + // Test syntax + let add = Regex { + int + "+" + int + } + let content = { add } + + let m = "2020+16".wholeMatch { + int + "+" + int + } + XCTAssertEqual(m?.output.0, "2020+16") + XCTAssertEqual(m?.output.1, 2020) + XCTAssertEqual(m?.output.2, 16) + + let m1 = "2020+16".wholeMatch(of: content) + XCTAssertEqual(m1?.output.0, m?.output.0) + XCTAssertEqual(m1?.output.1, m?.output.1) + XCTAssertEqual(m1?.output.2, m?.output.2) + + let firstMatch = "2020+16 0+0".firstMatch(of: content) + XCTAssertEqual(firstMatch?.output.0, "2020+16") + XCTAssertEqual(firstMatch?.output.1, 2020) + XCTAssertEqual(firstMatch?.output.2, 16) + + let prefix = "2020+16 0+0".prefixMatch(of: content) + XCTAssertEqual(prefix?.output.0, "2020+16") + XCTAssertEqual(prefix?.output.1, 2020) + XCTAssertEqual(prefix?.output.2, 16) + + try expectMatch( + .whole, + ("0+0", ("0+0", 0, 0)), + ("2020+16", ("2020+16", 2020, 16)), + ("-2020+16", nil), + ("2020+16+0+0", nil), + matchType: (Substring, Int, Int).self, + equivalence: == + ) { + int + "+" + int + } + + try expectMatch( + .prefix, + ("0+0", ("0+0", 0, 0)), + ("2020+16", ("2020+16", 2020, 16)), + ("-2020+16", nil), + ("2020+16+0+0", ("2020+16", 2020, 16)), + matchType: (Substring, Int, Int).self, + equivalence: == + ) { + int + "+" + int + } + + try expectMatch( + .first, + ("0+0", ("0+0", 0, 0)), + ("2020+16", ("2020+16", 2020, 16)), + ("-2020+16", ("2020+16", 2020, 16)), + ("2020+16+0+0", ("2020+16", 2020, 16)), + matchType: (Substring, Int, Int).self, + equivalence: == + ) { + int + "+" + int + } + } + + func testStartsAndContains() throws { + let fam = "👨‍👩‍👧‍👦👨‍👨‍👧‍👧 we Ⓡ family" + let startsWithGrapheme = fam.starts { + OneOrMore(.anyGrapheme) + OneOrMore(.whitespace) + } + XCTAssertEqual(startsWithGrapheme, true) + + let containsDads = fam.contains { + "👨‍👨‍👧‍👧" + } + XCTAssertEqual(containsDads, true) + + let content = { + Regex { + OneOrMore(.anyGrapheme) + OneOrMore(.whitespace) + } + } + XCTAssertEqual(fam.starts(with: content), true) + XCTAssertEqual(fam.contains(content), true) + + let int = Capture(OneOrMore(.digit)) { Int($0)! } + + try expectEqual( + .starts, + ("9+16, 0+3, 5+5, 99+1", true), + ("-9+16, 0+3, 5+5, 99+1", false), + (" 9+16", false), + ("a+b, c+d", false), + ("", false) + ) { + int + "+" + int + } + + try expectEqual( + .contains, + ("9+16, 0+3, 5+5, 99+1", true), + ("-9+16, 0+3, 5+5, 99+1", true), + (" 9+16", true), + ("a+b, c+d", false), + ("", false) + ) { + int + "+" + int + } + } + + func testTrim() throws { + let int = Capture(OneOrMore(.digit)) { Int($0)! } + + // Test syntax + let code = "(408)888-8888".trimmingPrefix { + "(" + OneOrMore(.digit) + ")" + } + XCTAssertEqual(code, Substring("888-8888")) + + var mutable = "👨‍👩‍👧‍👦 we Ⓡ family" + mutable.trimPrefix { + .anyGrapheme + ZeroOrMore(.whitespace) + } + XCTAssertEqual(mutable, "we Ⓡ family") + + try expectEqual( + .trimmingPrefix, + ("9+16 0+3 5+5 99+1", Substring(" 0+3 5+5 99+1")), + ("a+b 0+3 5+5 99+1", Substring("a+b 0+3 5+5 99+1")), + ("0+3+5+5+99+1", Substring("+5+5+99+1")), + ("", "") + ) { + int + "+" + int + } + } + + func testReplace() { + // Test no ambiguitiy using the trailing closure + var replaced: String + let str = "9+16, 0+3, 5+5, 99+1" + replaced = str.replacing(with: "🔢") { + OneOrMore(.digit) + "+" + OneOrMore(.digit) + } + XCTAssertEqual(replaced, "🔢, 🔢, 🔢, 🔢") + + replaced = str.replacing( + with: "🔢", + subrange: str.startIndex.. Date: Thu, 21 Apr 2022 10:40:26 -0700 Subject: [PATCH 113/133] Revise doc comments for API reference style. - Fix spelling error in parameter name (invertion --> inversion). - Add docs for parameters and return values. - Use indicative instead of imperative for method/function/initializer abstracts. (Match a regex. --> Matches a regex.) - Don't use code voice in abstracts, or symbol names as English nouns. - Use contractions per Apple style. - Turn /// comments that contain notes for this API's implementers into plain // comments, to omit that content from the docs. Move them before the /// comments, to keep doc comments immediately adjacent to the declaration they documents. --- Sources/RegexBuilder/CharacterClass.swift | 6 +- Sources/RegexBuilder/DSL.swift | 11 ++-- Sources/_RegexParser/Regex/AST/AST.swift | 21 ++++--- Sources/_RegexParser/Regex/AST/Atom.swift | 14 +++-- .../Regex/AST/CustomCharClass.swift | 5 +- Sources/_RegexParser/Regex/AST/Group.swift | 13 +++-- .../Regex/AST/MatchingOptions.swift | 11 ++-- .../Regex/AST/Quantification.swift | 2 +- .../Regex/Parse/CaptureStructure.swift | 3 +- Sources/_RegexParser/Regex/Parse/Parse.swift | 4 +- Sources/_RegexParser/Regex/Parse/Source.swift | 10 ++-- .../Regex/Parse/SourceLocation.swift | 8 +-- .../Regex/Parse/SyntaxOptions.swift | 28 +++++----- .../_RegexParser/Regex/Printing/DumpAST.swift | 7 ++- .../Regex/Printing/PrettyPrinter.swift | 50 ++++++++++------- .../Regex/Printing/PrintAsCanonical.swift | 16 ++++-- Sources/_RegexParser/Utility/Misc.swift | 14 +++-- .../_RegexParser/Utility/MissingUnicode.swift | 30 ++++++---- .../Algorithms/Algorithms/Split.swift | 6 +- .../Algorithms/Algorithms/StartsWith.swift | 3 +- .../_StringProcessing/PrintAsPattern.swift | 2 +- .../Regex/AnyRegexOutput.swift | 23 +++++--- Sources/_StringProcessing/Regex/Core.swift | 2 +- Sources/_StringProcessing/Regex/DSLTree.swift | 14 ++--- Sources/_StringProcessing/Regex/Match.swift | 55 +++++++++++-------- Sources/_StringProcessing/Regex/Options.swift | 51 +++++++++++++---- .../_CharacterClassModel.swift | 21 ++++--- 27 files changed, 269 insertions(+), 161 deletions(-) diff --git a/Sources/RegexBuilder/CharacterClass.swift b/Sources/RegexBuilder/CharacterClass.swift index b7d8454bb..3a96ba363 100644 --- a/Sources/RegexBuilder/CharacterClass.swift +++ b/Sources/RegexBuilder/CharacterClass.swift @@ -100,7 +100,7 @@ extension RegexComponent where Self == CharacterClass { members: s.map { .atom(.char($0)) })) } - /// Returns a character class that matches any unicode scalar in the given + /// Returns a character class that matches any Unicode scalar in the given /// sequence. public static func anyOf(_ s: S) -> CharacterClass where S.Element == UnicodeScalar @@ -118,7 +118,7 @@ extension CharacterClass { } } -/// Range syntax for characters in `CharacterClass`es. +/// Returns a character class that includes the characters in the given range. @available(SwiftStdlib 5.7, *) public func ...(lhs: Character, rhs: Character) -> CharacterClass { let range: DSLTree.CustomCharacterClass.Member = .range(.char(lhs), .char(rhs)) @@ -126,7 +126,7 @@ public func ...(lhs: Character, rhs: Character) -> CharacterClass { return CharacterClass(ccc) } -/// Range syntax for unicode scalars in `CharacterClass`es. +/// Returns a character class that includes the Unicode scalars in the given range. @_disfavoredOverload @available(SwiftStdlib 5.7, *) public func ...(lhs: UnicodeScalar, rhs: UnicodeScalar) -> CharacterClass { diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 62aacc4af..10590fb74 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -95,8 +95,8 @@ extension UnicodeScalar: RegexComponent { // Note: Quantifiers are currently gyb'd. extension DSLTree.Node { - /// Generates a DSLTree node for a repeated range of the given DSLTree node. - /// Individual public API functions are in the generated Variadics.swift file. + // Individual public API functions are in the generated Variadics.swift file. + /// Generates a DSL tree node for a repeated range of the given node. @available(SwiftStdlib 5.7, *) static func repeating( _ range: Range, @@ -251,8 +251,10 @@ public struct TryCapture: _BuiltinRegexComponent { // MARK: - Groups -/// An atomic group, i.e. opens a local backtracking scope which, upon successful exit, -/// discards any remaining backtracking points from within the scope +/// An atomic group. +/// +/// This group opens a local backtracking scope which, upon successful exit, +/// discards any remaining backtracking points from within the scope. @available(SwiftStdlib 5.7, *) public struct Local: _BuiltinRegexComponent { public var regex: Regex @@ -265,6 +267,7 @@ public struct Local: _BuiltinRegexComponent { // MARK: - Backreference @available(SwiftStdlib 5.7, *) +/// A backreference. public struct Reference: RegexComponent { let id = ReferenceID() diff --git a/Sources/_RegexParser/Regex/AST/AST.swift b/Sources/_RegexParser/Regex/AST/AST.swift index 409d5a7ee..eae393289 100644 --- a/Sources/_RegexParser/Regex/AST/AST.swift +++ b/Sources/_RegexParser/Regex/AST/AST.swift @@ -9,8 +9,9 @@ // //===----------------------------------------------------------------------===// -/// A regex abstract syntax tree. This is a top-level type that stores the root -/// node. +/// A regex abstract syntax tree. +/// +/// This is a top-level type that stores the root node. public struct AST: Hashable { public var root: AST.Node public var globalOptions: GlobalMatchingOptionSequence? @@ -22,7 +23,7 @@ public struct AST: Hashable { } extension AST { - /// Whether this AST tree has nested somewhere inside it a capture. + /// Whether this AST tree contains at least one capture nested inside of it. public var hasCapture: Bool { root.hasCapture } /// The capture structure of this AST tree. @@ -94,7 +95,9 @@ extension AST.Node { _associatedValue as? T } - /// If this node is a parent node, access its children + /// The child nodes of this node. + /// + /// If the node isn't a parent node, this value is `nil`. public var children: [AST.Node]? { return (_associatedValue as? _ASTParent)?.children } @@ -103,7 +106,7 @@ extension AST.Node { _associatedValue.location } - /// Whether this node is "trivia" or non-semantic, like comments + /// Whether this node is trivia or non-semantic, like comments. public var isTrivia: Bool { switch self { case .trivia: return true @@ -111,7 +114,7 @@ extension AST.Node { } } - /// Whether this node has nested somewhere inside it a capture + /// Whether this node contains at least one capture nested inside of it. public var hasCapture: Bool { switch self { case .group(let g) where g.kind.value.isCapturing: @@ -122,7 +125,7 @@ extension AST.Node { return self.children?.any(\.hasCapture) ?? false } - /// Whether this AST node may be used as the operand of a quantifier such as + /// Whether this node may be used as the operand of a quantifier such as /// `?`, `+` or `*`. public var isQuantifiable: Bool { switch self { @@ -203,7 +206,9 @@ extension AST { } } - /// An Oniguruma absent function. This is used to model a pattern which should + /// An Oniguruma absent function. + /// + /// This is used to model a pattern which should /// not be matched against across varying scopes. public struct AbsentFunction: Hashable, _ASTNode { public enum Start: Hashable { diff --git a/Sources/_RegexParser/Regex/AST/Atom.swift b/Sources/_RegexParser/Regex/AST/Atom.swift index 1f6043d72..e17ce68bb 100644 --- a/Sources/_RegexParser/Regex/AST/Atom.swift +++ b/Sources/_RegexParser/Regex/AST/Atom.swift @@ -415,7 +415,7 @@ extension AST.Atom.CharacterProperty { } extension AST.Atom { - /// Anchors and other built-in zero-width assertions + /// Anchors and other built-in zero-width assertions. @frozen public enum AssertionKind: String { /// \A @@ -574,7 +574,7 @@ extension AST.Atom { } extension AST.Atom.Callout { - /// A tag specifier `[...]` which may appear in an Oniguruma callout. + /// A tag specifier `[...]` that can appear in an Oniguruma callout. public struct OnigurumaTag: Hashable { public var leftBracket: SourceLocation public var name: AST.Located @@ -668,8 +668,10 @@ extension AST.Atom.EscapedBuiltin { } extension AST.Atom { - /// Retrieve the character value of the atom if it represents a literal - /// character or unicode scalar, nil otherwise. + /// Retrieves the character value of the atom. + /// + /// If the atom doesn't represent a literal character or a Unicode scalar, + /// this value is `nil`. public var literalCharacterValue: Character? { switch kind { case .char(let c): @@ -711,9 +713,9 @@ extension AST.Atom { } } - /// Produce a string literal representation of the atom, if possible + /// A string literal representation of the atom, if possible. /// - /// Individual characters will be returned, Unicode scalars will be + /// Individual characters are returned as-is, and Unicode scalars are /// presented using "\u{nnnn}" syntax. public var literalStringValue: String? { switch kind { diff --git a/Sources/_RegexParser/Regex/AST/CustomCharClass.swift b/Sources/_RegexParser/Regex/AST/CustomCharClass.swift index 19e72aef5..c1dd4c620 100644 --- a/Sources/_RegexParser/Regex/AST/CustomCharClass.swift +++ b/Sources/_RegexParser/Regex/AST/CustomCharClass.swift @@ -104,8 +104,9 @@ extension CustomCC.Member { } extension AST.CustomCharacterClass { - /// Strip trivia from the character class members. This does not recurse into - /// nested custom character classes. + /// Strips trivia from the character class members. + /// + /// This method doesn't recurse into nested custom character classes. public var strippingTriviaShallow: Self { var copy = self copy.members = copy.members.filter(\.isSemantic) diff --git a/Sources/_RegexParser/Regex/AST/Group.swift b/Sources/_RegexParser/Regex/AST/Group.swift index a8c4f8b0f..8ecaadeda 100644 --- a/Sources/_RegexParser/Regex/AST/Group.swift +++ b/Sources/_RegexParser/Regex/AST/Group.swift @@ -78,6 +78,7 @@ extension AST { } extension AST.Group.Kind { + /// Whether the group is a capturing group. public var isCapturing: Bool { switch self { case .capture, .namedCapture, .balancedCapture: return true @@ -85,7 +86,9 @@ extension AST.Group.Kind { } } - /// If this is a named group, its name, `nil` otherwise. + /// The name of the group. + /// + /// If the group doesn't have a name, this value is `nil`. public var name: String? { switch self { case .namedCapture(let name): return name.value @@ -96,9 +99,11 @@ extension AST.Group.Kind { } extension AST.Group.Kind { - /// If this group is a lookaround assertion, return its direction - /// and whether it is positive or negative. Otherwise returns - /// `nil`. + /// The direction of a lookaround assertion + /// and an indication of whether the assertion is positive or negative. + /// + /// If the group isn't a lookaheand or lookbehind assertion, + /// this value is `nil`. public var lookaroundKind: (forwards: Bool, positive: Bool)? { switch self { case .lookahead: return (true, true) diff --git a/Sources/_RegexParser/Regex/AST/MatchingOptions.swift b/Sources/_RegexParser/Regex/AST/MatchingOptions.swift index 8e4b31bc5..e779c39fb 100644 --- a/Sources/_RegexParser/Regex/AST/MatchingOptions.swift +++ b/Sources/_RegexParser/Regex/AST/MatchingOptions.swift @@ -10,7 +10,7 @@ //===----------------------------------------------------------------------===// extension AST { - /// An option written in source that changes matching semantics. + /// An option, written in source, that changes matching semantics. public struct MatchingOption: Hashable { public enum Kind { // PCRE options @@ -83,7 +83,7 @@ extension AST { } } - /// A sequence of matching options written in source. + /// A sequence of matching options, written in source. public struct MatchingOptionSequence: Hashable { /// If the sequence starts with a caret '^', its source location, or nil /// otherwise. If this is set, it indicates that all the matching options @@ -138,8 +138,11 @@ extension AST.MatchingOptionSequence: _ASTPrintable { } extension AST { - /// Global matching option specifiers. Unlike `MatchingOptionSequence`, - /// these must appear at the start of the pattern, and apply globally. + /// Global matching option specifiers. + /// + /// Unlike `MatchingOptionSequence`, + /// these options must appear at the start of the pattern, + /// and they apply to the entire pattern. public struct GlobalMatchingOption: _ASTNode, Hashable { /// Determines the definition of a newline for the '.' character class and /// when parsing end-of-line comments. diff --git a/Sources/_RegexParser/Regex/AST/Quantification.swift b/Sources/_RegexParser/Regex/AST/Quantification.swift index f2189cb38..fa7e4de82 100644 --- a/Sources/_RegexParser/Regex/AST/Quantification.swift +++ b/Sources/_RegexParser/Regex/AST/Quantification.swift @@ -59,7 +59,7 @@ extension AST { /// MARK: - Semantic API extension AST.Quantification.Amount { - /// Get the bounds + /// The bounds. public var bounds: (atLeast: Int, atMost: Int?) { switch self { case .zeroOrMore: return (0, nil) diff --git a/Sources/_RegexParser/Regex/Parse/CaptureStructure.swift b/Sources/_RegexParser/Regex/Parse/CaptureStructure.swift index 8298dc207..9cb31c7d9 100644 --- a/Sources/_RegexParser/Regex/Parse/CaptureStructure.swift +++ b/Sources/_RegexParser/Regex/Parse/CaptureStructure.swift @@ -286,10 +286,11 @@ extension CaptureStructure { MemoryLayout.stride + inputUTF8CodeUnitCount + 1 } - /// Encode the capture structure to the given buffer as a serialized + /// Encodes the capture structure to the given buffer as a serialized /// representation. /// /// The encoding rules are as follows: + /// /// ``` /// encode(〚`T`〛) ==> , 〚`T`〛, .end /// 〚`T` (atom)〛 ==> .atom diff --git a/Sources/_RegexParser/Regex/Parse/Parse.swift b/Sources/_RegexParser/Regex/Parse/Parse.swift index a2790924a..ec6e1c26c 100644 --- a/Sources/_RegexParser/Regex/Parse/Parse.swift +++ b/Sources/_RegexParser/Regex/Parse/Parse.swift @@ -577,8 +577,8 @@ fileprivate func defaultSyntaxOptions( } } -/// Parse a given regex string with delimiters, inferring the syntax options -/// from the delimiter used. +/// Parses a given regex string with delimiters, inferring the syntax options +/// from the delimiters used. public func parseWithDelimiters( _ regex: S ) throws -> AST where S.SubSequence == Substring { diff --git a/Sources/_RegexParser/Regex/Parse/Source.swift b/Sources/_RegexParser/Regex/Parse/Source.swift index 6eac16395..23cc0497d 100644 --- a/Sources/_RegexParser/Regex/Parse/Source.swift +++ b/Sources/_RegexParser/Regex/Parse/Source.swift @@ -9,10 +9,12 @@ // //===----------------------------------------------------------------------===// -/// The source given to a parser. This can be bytes in memory, a file on disk, -/// something streamed over a network connection, etc. +// For now, we use String as the source while prototyping... + +/// The source of text being given to a parser. /// -/// For now, we use String... +/// This can be bytes in memory, a file on disk, +/// something streamed over a network connection, and so on. /// public struct Source { var input: Input @@ -37,7 +39,7 @@ extension Source { public typealias Input = String // for wrapper... public typealias Char = Character // for wrapper... - /// A precise point in the input, commonly used for bounded ranges + /// A precise point in the input, commonly used for bounded ranges. public typealias Position = String.Index } diff --git a/Sources/_RegexParser/Regex/Parse/SourceLocation.swift b/Sources/_RegexParser/Regex/Parse/SourceLocation.swift index a58473c96..eb51643bd 100644 --- a/Sources/_RegexParser/Regex/Parse/SourceLocation.swift +++ b/Sources/_RegexParser/Regex/Parse/SourceLocation.swift @@ -62,7 +62,7 @@ public protocol LocatedErrorProtocol: Error { } extension Source { - /// An error with source location info + /// An error that includes information about the location in source code. public struct LocatedError: Error, LocatedErrorProtocol { public let error: E public let location: SourceLocation @@ -77,10 +77,10 @@ extension Source { } } - /// Located value: a value wrapped with a source range + /// A value wrapped with a source range. /// - /// Note: source location is part of value identity, so that the same - /// e.g. `Character` appearing twice can be stored in a data structure + /// Note: Source location is part of value identity so that, for example, the + /// same `Character` value appearing twice can be stored in a data structure /// distinctly. To ignore source locations, use `.value` directly. public struct Located { public var value: T diff --git a/Sources/_RegexParser/Regex/Parse/SyntaxOptions.swift b/Sources/_RegexParser/Regex/Parse/SyntaxOptions.swift index b7c09ea1c..0a6270f1b 100644 --- a/Sources/_RegexParser/Regex/Parse/SyntaxOptions.swift +++ b/Sources/_RegexParser/Regex/Parse/SyntaxOptions.swift @@ -31,31 +31,31 @@ public struct SyntaxOptions: OptionSet { [.endOfLineComments, .nonSemanticWhitespace] } + // NOTE: Currently, this means we have raw quotes. + // Better would be to have real Swift string delimiter parsing logic. + /// `'a "." b' == '/a\Q.\Eb/'` - /// - /// NOTE: Currently, this means we have raw quotes. - /// Better would be to have real Swift string delimiter parsing logic. public static var experimentalQuotes: Self { Self(1 << 2) } + // NOTE: traditional comments are not nested. Currently, we are neither. + // Traditional comments can't have `)`, not even escaped in them either, we + // can. Traditional comments can have `*/` in them, we can't without + // escaping. We don't currently do escaping. + /// `'a /* comment */ b' == '/a(?#. comment )b/'` - /// - /// NOTE: traditional comments are not nested. Currently, we are neither. - /// Traditional comments can't have `)`, not even escaped in them either, we - /// can. Traditional comments can have `*/` in them, we can't without - /// escaping. We don't currently do escaping. public static var experimentalComments: Self { Self(1 << 3) } /// ``` - /// 'a{n...m}' == '/a{n,m}/' - /// 'a{n...*)` - /// `(_: .*)` == `(?:.*)` + /// `(_: .*)` == `(?:.*)` public static var experimentalCaptures: Self { Self(1 << 5) } /// The default syntax for a multi-line regex literal. diff --git a/Sources/_RegexParser/Regex/Printing/DumpAST.swift b/Sources/_RegexParser/Regex/Printing/DumpAST.swift index 8565b14e9..a9cf6b424 100644 --- a/Sources/_RegexParser/Regex/Printing/DumpAST.swift +++ b/Sources/_RegexParser/Regex/Printing/DumpAST.swift @@ -9,10 +9,11 @@ // //===----------------------------------------------------------------------===// -/// AST entities can be pretty-printed or dumped +/// AST entities that can be pretty-printed or dumped. /// -/// Alternative: just use `description` for pretty-print -/// and `debugDescription` for dump +/// As an alternative to this protocol, +/// you can also use the `description` to pretty-print an AST, +/// and `debugDescription` for to dump a debugging representation. public protocol _ASTPrintable: CustomStringConvertible, CustomDebugStringConvertible diff --git a/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift b/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift index f1d8c83b0..c06643aee 100644 --- a/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift +++ b/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift @@ -9,17 +9,25 @@ // //===----------------------------------------------------------------------===// -/// Track and handle state relevant to pretty-printing ASTs. +/// State used when to pretty-printing regex ASTs. public struct PrettyPrinter { // Configuration - /// Cut off pattern conversion after this many levels + /// The maximum number number of levels, from the root of the tree, + /// at which to perform pattern conversion. + /// + /// A `nil` value indicates that there is no maximum, + /// and pattern conversion always takes place. public var maxTopDownLevels: Int? - /// Cut off pattern conversion after this tree height + /// The maximum number number of levels, from the leaf nodes of the tree, + /// at which to perform pattern conversion. + /// + /// A `nil` value indicates that there is no maximum, + /// and pattern conversion always takes place. public var minBottomUpLevels: Int? - /// How many spaces to indent with ("tab-width") + /// The number of spaces used for indentation. public var indentWidth = 2 // Internal state @@ -46,25 +54,27 @@ extension PrettyPrinter { self.minBottomUpLevels = minBottomUpLevels } - /// Output a string directly, without termination, without - /// indentation, and without updating _any_ internal state. + /// Outputs a string directly, without termination or + /// indentation, and without updating any internal state. /// /// This is the low-level interface to the pret /// - /// NOTE: If `s` includes a newline, even at the end, - /// this function will not update any tracking state. + /// - Note: If `s` includes a newline, even at the end, + /// this method does not update any tracking state. public mutating func output(_ s: String) { result += s } - /// Terminate a line, updating any relevant state + /// Terminates a line, updating any relevant state. public mutating func terminateLine() { output("\n") startOfLine = true } - /// Indent a new line, if at the start of a line, otherwise - /// does nothing. Updates internal state. + /// Indents a new line, if at the start of a line, otherwise + /// does nothing. + /// + /// This function updates internal state. public mutating func indent() { guard startOfLine else { return } let numCols = indentLevel * indentWidth @@ -72,7 +82,9 @@ extension PrettyPrinter { startOfLine = false } - // Finish, flush, and clear. Returns the rendered output + // Finish, flush, and clear. + // + // - Returns: The rendered output. public mutating func finish() -> String { defer { result = "" } return result @@ -85,18 +97,18 @@ extension PrettyPrinter { extension PrettyPrinter { /// Print out a new entry. /// - /// This will property indent `s`, update any internal state, - /// and will also terminate the current line. + /// This method indents `s`, updates any internal state, + /// and terminates the current line. public mutating func print(_ s: String) { indent() output("\(s)") terminateLine() } - /// Print out a new entry by invoking `f` until it returns `nil`. + /// Prints out a new entry by invoking `f` until it returns `nil`. /// - /// This will property indent, update any internal state, - /// and will also terminate the current line. + /// This method indents `s`, updates any internal state, + /// and terminates the current line. public mutating func printLine(_ f: () -> String?) { // TODO: What should we do if `f` never returns non-nil? indent() @@ -106,7 +118,7 @@ extension PrettyPrinter { terminateLine() } - /// Execute `f` at one increased level of indentation + /// Executes `f` at one increased level of indentation. public mutating func printIndented( _ f: (inout Self) -> () ) { @@ -115,7 +127,7 @@ extension PrettyPrinter { self.indentLevel -= 1 } - /// Execute `f` inside an indented "block", which has a header + /// Executes `f` inside an indented block, which has a header /// and delimiters. public mutating func printBlock( _ header: String, diff --git a/Sources/_RegexParser/Regex/Printing/PrintAsCanonical.swift b/Sources/_RegexParser/Regex/Printing/PrintAsCanonical.swift index ab961ba51..59c0cc04a 100644 --- a/Sources/_RegexParser/Regex/Printing/PrintAsCanonical.swift +++ b/Sources/_RegexParser/Regex/Printing/PrintAsCanonical.swift @@ -12,7 +12,7 @@ // TODO: Round-tripping tests extension AST { - /// Render using Swift's preferred regex literal syntax + /// Renders using Swift's preferred regex literal syntax. public func renderAsCanonical( showDelimiters delimiters: Bool = false, terminateLine: Bool = false @@ -27,7 +27,7 @@ extension AST { } extension AST.Node { - /// Render using Swift's preferred regex literal syntax + /// Renders using Swift's preferred regex literal syntax. public func renderAsCanonical( showDelimiters delimiters: Bool = false, terminateLine: Bool = false @@ -38,8 +38,12 @@ extension AST.Node { } extension PrettyPrinter { - /// Will output `ast` in canonical form, taking care to - /// also indent and terminate the line (updating internal state) + /// Outputs a regular expression abstract syntax tree in canonical form, + /// indenting and terminating the line, and updating its internal state. + /// + /// - Parameter ast: The abstract syntax tree of the regular expression being output. + /// - Parameter delimiters: Whether to include commas between items. + /// - Parameter terminateLine: Whether to include terminate the line. public mutating func printAsCanonical( _ ast: AST, delimiters: Bool = false, @@ -57,8 +61,8 @@ extension PrettyPrinter { } } - /// Output the `ast` in canonical form, does not indent, terminate, - /// or affect internal state + /// Outputs a regular expression abstract syntax tree in canonical form, + /// without indentation, line termation, or affecting its internal state. mutating func outputAsCanonical(_ ast: AST.Node) { switch ast { case let .alternation(a): diff --git a/Sources/_RegexParser/Utility/Misc.swift b/Sources/_RegexParser/Utility/Misc.swift index 55d3d3adc..bd9bc665e 100644 --- a/Sources/_RegexParser/Utility/Misc.swift +++ b/Sources/_RegexParser/Utility/Misc.swift @@ -111,8 +111,11 @@ extension Collection { } extension Collection where Element: Equatable { - /// Attempt to drop a given prefix from the collection, returning the - /// resulting subsequence, or `nil` if the prefix does not match. + /// Attempts to drop a given prefix from the collection. + /// + /// - Parameter other: The collection that contains the prefix. + /// - Returns: The resulting subsequence, + /// or `nil` if the prefix doesn't match. public func tryDropPrefix( _ other: C ) -> SubSequence? where C.Element == Element { @@ -121,8 +124,11 @@ extension Collection where Element: Equatable { return dropFirst(prefixCount) } - /// Attempt to drop a given suffix from the collection, returning the - /// resulting subsequence, or `nil` if the suffix does not match. + /// Attempts to drop a given suffix from the collection. + /// + /// - Parameter other: The collection that contains the suffix. + /// - Returns: The resulting subsequence, + /// or `nil` if the prefix doesn't match. public func tryDropSuffix( _ other: C ) -> SubSequence? where C.Element == Element { diff --git a/Sources/_RegexParser/Utility/MissingUnicode.swift b/Sources/_RegexParser/Utility/MissingUnicode.swift index 4d819806b..b1a4a07ff 100644 --- a/Sources/_RegexParser/Utility/MissingUnicode.swift +++ b/Sources/_RegexParser/Utility/MissingUnicode.swift @@ -12,13 +12,13 @@ // MARK: - Missing stdlib API extension Unicode { + // Note: The `Script` enum includes the "meta" script type "Katakana_Or_Hiragana", which + // isn't defined by https://www.unicode.org/Public/UCD/latest/ucd/Scripts.txt, + // but is defined by https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt. + // We may want to split it out, as it's the only case that is a union of + // other script types. + /// Character script types. - /// - /// Note this includes the "meta" script type "Katakana_Or_Hiragana", which - /// isn't defined by https://www.unicode.org/Public/UCD/latest/ucd/Scripts.txt, - /// but is defined by https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt. - /// We may want to split it out, as it's the only case that is a union of - /// other script types. @frozen public enum Script: String, Hashable { case adlam = "Adlam" @@ -254,7 +254,8 @@ extension Unicode { case spaceSeparator = "Zs" } - /// A list of unicode properties that can either be true or false. + /// A list of Unicode properties that can either be true or false. + /// /// https://www.unicode.org/Public/UCD/latest/ucd/PropertyAliases.txt @frozen public enum BinaryProperty: String, Hashable { @@ -328,9 +329,10 @@ extension Unicode { } } +// TODO: These should become aliases for the Block (blk) Unicode character +// property. + /// Oniguruma properties that are not covered by Unicode spellings. -/// TODO: These should become aliases for the Block (blk) Unicode character -/// property. @frozen public enum OnigurumaSpecialProperty: String, Hashable { case inBasicLatin = "In_Basic_Latin" @@ -657,18 +659,24 @@ public enum OnigurumaSpecialProperty: String, Hashable { } extension Character { + /// Whether this character represents an octal (base 8) digit, + /// for the purposes of pattern parsing. public var isOctalDigit: Bool { ("0"..."7").contains(self) } + /// Whether this character represents a word character, + /// for the purposes of pattern parsing. public var isWordCharacter: Bool { isLetter || isNumber || self == "_" } - /// Whether this character represents whitespace for the purposes of pattern - /// parsing. + /// Whether this character represents whitespace, + /// for the purposes of pattern parsing. public var isPatternWhitespace: Bool { return unicodeScalars.first!.properties.isPatternWhitespace } } extension UnicodeScalar { + /// Whether this character represents a printable ASCII character, + /// for the purposes of pattern parsing. public var isPrintableASCII: Bool { // Exclude non-printables before the space character U+20, and anything // including and above the DEL character U+7F. diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift index 97d8c80dd..df121d8c5 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -299,9 +299,10 @@ extension Collection where Element: Equatable { // FIXME: Return `some Collection` for SE-0346 /// Returns the longest possible subsequences of the collection, in order, /// around elements equal to the given separator. + /// /// - Parameter separator: The element to be split upon. /// - Returns: A collection of subsequences, split from this collection's - /// elements. + /// elements. @available(SwiftStdlib 5.7, *) public func split( separator: C, @@ -373,9 +374,10 @@ extension BidirectionalCollection where SubSequence == Substring { // FIXME: Return `some Collection` for SE-0346 /// Returns the longest possible subsequences of the collection, in order, /// around elements equal to the given separator. + /// /// - Parameter separator: A regex describing elements to be split upon. /// - Returns: A collection of substrings, split from this collection's - /// elements. + /// elements. @_disfavoredOverload public func split( separator: R, diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift index 0dd91f360..2f45a734b 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift @@ -51,9 +51,10 @@ extension BidirectionalCollection where Element: Equatable { extension BidirectionalCollection where SubSequence == Substring { /// Returns a Boolean value indicating whether the initial elements of the /// sequence are the same as the elements in the specified regex. + /// /// - Parameter regex: A regex to compare to this sequence. /// - Returns: `true` if the initial elements of the sequence matches the - /// beginning of `regex`; otherwise, `false`. + /// beginning of `regex`; otherwise, `false`. public func starts(with regex: R) -> Bool { starts(with: RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index 91626eb5c..ff85e38f1 100644 --- a/Sources/_StringProcessing/PrintAsPattern.swift +++ b/Sources/_StringProcessing/PrintAsPattern.swift @@ -19,7 +19,7 @@ @_spi(PatternConverter) extension AST { - /// Render as a Pattern DSL + /// Renders as a Pattern DSL. @_spi(PatternConverter) public func renderAsBuilderDSL( maxTopDownLevels: Int? = nil, diff --git a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift index 0d018aa81..3dbe9d84e 100644 --- a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift +++ b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift @@ -13,7 +13,9 @@ @available(SwiftStdlib 5.7, *) extension Regex where Output == AnyRegexOutput { - /// Parse and compile `pattern`, resulting in an existentially-typed capture list. + /// Parses and compiles a regular expression, resulting in an existentially-typed capture list. + /// + /// - Parameter pattern: The regular expression. public init(_ pattern: String) throws { self.init(ast: try parse(pattern, .traditional)) } @@ -21,7 +23,10 @@ extension Regex where Output == AnyRegexOutput { @available(SwiftStdlib 5.7, *) extension Regex { - /// Parse and compile `pattern`, resulting in a strongly-typed capture list. + /// Parses and compiles a regular expression. + /// + /// - Parameter pattern: The regular expression. + /// - Parameter as: The desired type for the output. public init( _ pattern: String, as: Output.Type = Output.self @@ -32,7 +37,7 @@ extension Regex { @available(SwiftStdlib 5.7, *) extension Regex.Match where Output == AnyRegexOutput { - // Ensures `.0` always refers to the whole match. + /// Accesses the whole match using the `.0` syntax. public subscript( dynamicMember keyPath: KeyPath<(Substring, _doNotUse: ()), Substring> ) -> Substring { @@ -44,7 +49,7 @@ extension Regex.Match where Output == AnyRegexOutput { } } -/// A type-erased regex output +/// A type-erased regex output. @available(SwiftStdlib 5.7, *) public struct AnyRegexOutput { let input: String @@ -67,7 +72,7 @@ extension AnyRegexOutput { /// Creates a type-erased regex output from an existing output. /// /// Use this initializer to fit a regex with strongly typed captures into the - /// use site of a dynamic regex, i.e. one that was created from a string. + /// use site of a dynamic regex, like one that was created from a string. public init(_ match: Regex.Match) { // Note: We use type equality instead of `match.output as? ...` to prevent // unexpected optional flattening. @@ -84,7 +89,7 @@ extension AnyRegexOutput { /// /// - Parameter type: The expected output type. /// - Returns: The output, if the underlying value can be converted to the - /// output type, or nil otherwise. + /// output type; otherwise `nil`. public func `as`(_ type: Output.Type) -> Output? { let elements = _elements.map { StructuredCapture( @@ -190,7 +195,7 @@ extension Regex.Match where Output == AnyRegexOutput { /// Creates a type-erased regex match from an existing match. /// /// Use this initializer to fit a regex match with strongly typed captures into the - /// use site of a dynamic regex match, i.e. one that was created from a string. + /// use site of a dynamic regex match, like one that was created from a string. public init(_ match: Regex.Match) { fatalError("FIXME: Not implemented") } @@ -199,8 +204,8 @@ extension Regex.Match where Output == AnyRegexOutput { /// types. /// /// - Parameter type: The expected output type. - /// - Returns: A match generic over the output type if the underlying values can be converted to the - /// output type. Returns `nil` otherwise. + /// - Returns: A match generic over the output type, if the underlying values + /// can be converted to the output type; otherwise, `nil`. public func `as`(_ type: Output.Type) -> Regex.Match? { fatalError("FIXME: Not implemented") } diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index 36d62f674..1f9a35dad 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -19,7 +19,7 @@ public protocol RegexComponent { var regex: Regex { get } } -/// A regex represents a string processing algorithm. +/// A regular expression. /// /// let regex = try Regex("a(.*)b") /// let match = "cbaxb".firstMatch(of: regex) diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index ce5beeaca..52eaeffb0 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -25,29 +25,29 @@ public struct DSLTree { extension DSLTree { @_spi(RegexBuilder) public indirect enum Node { - /// Try to match each node in order + /// Matches each node in order. /// /// ... | ... | ... case orderedChoice([Node]) - /// Match each node in sequence + /// Match each node in sequence. /// /// ... ... case concatenation([Node]) - /// Capture the result of a subpattern + /// Captures the result of a subpattern. /// /// (...), (?...) case capture( name: String? = nil, reference: ReferenceID? = nil, Node) - /// Match a (non-capturing) subpattern / group + /// Matches a noncapturing subpattern. case nonCapturingGroup(_AST.GroupKind, Node) // TODO: Consider splitting off grouped conditions, or have // our own kind - /// Match a choice of two nodes based on a condition + /// Matches a choice of two nodes, based on a condition. /// /// (?(cond) true-branch | false-branch) /// @@ -63,7 +63,7 @@ extension DSLTree { case atom(Atom) - /// Comments, non-semantic whitespace, etc + /// Comments, non-semantic whitespace, and so on. // TODO: Do we want this? Could be interesting case trivia(String) @@ -73,7 +73,7 @@ extension DSLTree { case quotedLiteral(String) - /// An embedded literal + /// An embedded literal. case regexLiteral(_AST.ASTNode) // TODO: What should we do here? diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 45df7aeaa..dd36c8823 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -19,7 +19,7 @@ extension Regex { public struct Match { let input: String - /// The range of the overall match + /// The range of the overall match. public let range: Range let rawCaptures: [StructuredCapture] @@ -34,7 +34,7 @@ extension Regex { @available(SwiftStdlib 5.7, *) extension Regex.Match { - /// The produced output from the match operation + /// The output produced from the match operation. public var output: Output { if Output.self == AnyRegexOutput.self { let wholeMatchAsCapture = StructuredCapture( @@ -62,12 +62,12 @@ extension Regex.Match { } } - /// Lookup a capture by name or number + /// Accesses a capture by its name or number. public subscript(dynamicMember keyPath: KeyPath) -> T { output[keyPath: keyPath] } - // Allows `.0` when `Match` is not a tuple. + /// Accesses a capture using the `.0` syntax, even when the match isn't a tuple. @_disfavoredOverload public subscript( dynamicMember keyPath: KeyPath<(Output, _doNotUse: ()), Output> @@ -88,44 +88,50 @@ extension Regex.Match { @available(SwiftStdlib 5.7, *) extension Regex { - /// Match a string in its entirety. + /// Matches a string in its entirety. /// - /// Returns `nil` if no match and throws on abort + /// - Parameter s: The string to match this regular expression against. + /// - Returns: The match, or `nil` if no match was found. public func wholeMatch(in s: String) throws -> Regex.Match? { try _match(s, in: s.startIndex.. Regex.Match? { try _match(s, in: s.startIndex.. Regex.Match? { try _firstMatch(s, in: s.startIndex.. Regex.Match? { try _match(s.base, in: s.startIndex.. Regex.Match? { try _match(s.base, in: s.startIndex.. Regex.Match? { try _firstMatch(s.base, in: s.startIndex..( of r: R ) -> Regex.Match? { try? r.regex.wholeMatch(in: self[...].base) } - /// Match part of the regex, starting at the beginning. - /// - Parameter r: The regex to match against. - /// - Returns: The match if there is one, or `nil` if none. + /// Checks for a match against the string, starting at its beginning. + /// + /// - Parameter r: The regular expression being matched. + /// - Returns: The match, or `nil` if no match was found. public func prefixMatch( of r: R ) -> Regex.Match? { @@ -183,6 +191,7 @@ extension BidirectionalCollection where SubSequence == Substring { extension RegexComponent { public static func ~=(regex: Self, input: String) -> Bool { input.wholeMatch(of: regex) != nil + try? r.regex.wholeMatch(in: self) } public static func ~=(regex: Self, input: Substring) -> Bool { diff --git a/Sources/_StringProcessing/Regex/Options.swift b/Sources/_StringProcessing/Regex/Options.swift index cb0fe044e..24d5c422e 100644 --- a/Sources/_StringProcessing/Regex/Options.swift +++ b/Sources/_StringProcessing/Regex/Options.swift @@ -13,35 +13,57 @@ @available(SwiftStdlib 5.7, *) extension RegexComponent { - /// Returns a regular expression that ignores casing when matching. + /// Returns a regular expression that ignores case when matching. + /// + /// - Parameter ignoresCase: A Boolean value indicating whether to ignore case. + /// - Returns: The modified regular expression. public func ignoresCase(_ ignoresCase: Bool = true) -> Regex { wrapInOption(.caseInsensitive, addingIf: ignoresCase) } - /// Returns a regular expression that only matches ASCII characters as "word - /// characters". + /// Returns a regular expression that matches only ASCII characters as word + /// characters. + /// + /// - Parameter useASCII: A Boolean value indicating whether to match only + /// ASCII characters as word characters. + /// - Returns: The modified regular expression. public func asciiOnlyWordCharacters(_ useASCII: Bool = true) -> Regex { wrapInOption(.asciiOnlyWord, addingIf: useASCII) } - /// Returns a regular expression that only matches ASCII characters as digits. + /// Returns a regular expression that matches only ASCII characters as digits. + /// + /// - Parameter useasciiOnlyDigits: A Boolean value indicating whether to + /// match only ASCII characters as digits. + /// - Returns: The modified regular expression. public func asciiOnlyDigits(_ useASCII: Bool = true) -> Regex { wrapInOption(.asciiOnlyDigit, addingIf: useASCII) } - /// Returns a regular expression that only matches ASCII characters as space + /// Returns a regular expression that matches only ASCII characters as space /// characters. + /// + /// - Parameter asciiOnlyWhitespace: A Boolean value indicating whether to + /// match only ASCII characters as space characters. + /// - Returns: The modified regular expression. public func asciiOnlyWhitespace(_ useASCII: Bool = true) -> Regex { wrapInOption(.asciiOnlySpace, addingIf: useASCII) } - /// Returns a regular expression that only matches ASCII characters when + /// Returns a regular expression that matches only ASCII characters when /// matching character classes. + /// + /// - Parameter useASCII: A Boolean value indicating whether to match only + /// ASCII characters when matching character classes. + /// - Returns: The modified regular expression. public func asciiOnlyCharacterClasses(_ useASCII: Bool = true) -> Regex { wrapInOption(.asciiOnlyPOSIXProps, addingIf: useASCII) } /// Returns a regular expression that uses the specified word boundary algorithm. + /// + /// - Parameter wordBoundaryKind: The algorithm to use for determining word boundaries. + /// - Returns: The modified regular expression. public func wordBoundaryKind(_ wordBoundaryKind: RegexWordBoundaryKind) -> Regex { wrapInOption(.unicodeWordBoundaries, addingIf: wordBoundaryKind == .unicodeLevel2) } @@ -51,6 +73,7 @@ extension RegexComponent { /// /// - Parameter dotMatchesNewlines: A Boolean value indicating whether `.` /// should match a newline character. + /// - Returns: The modified regular expression. public func dotMatchesNewlines(_ dotMatchesNewlines: Bool = true) -> Regex { wrapInOption(.singleLine, addingIf: dotMatchesNewlines) } @@ -65,6 +88,7 @@ extension RegexComponent { /// /// - Parameter matchLineEndings: A Boolean value indicating whether `^` and /// `$` should match the start and end of lines, respectively. + /// - Returns: The modified regular expression. public func anchorsMatchLineEndings(_ matchLineEndings: Bool = true) -> Regex { wrapInOption(.multiline, addingIf: matchLineEndings) } @@ -124,6 +148,9 @@ extension RegexComponent { /// // Prints "true" /// print(decomposed.contains(queRegexScalar)) /// // Prints "false" + /// + /// - Parameter semanticLevel: The semantics to use during matching. + /// - Returns: The modified regular expression. public func matchingSemantics(_ semanticLevel: RegexSemanticLevel) -> Regex { switch semanticLevel.base { case .graphemeCluster: @@ -144,14 +171,18 @@ public struct RegexSemanticLevel: Hashable { internal var base: Representation - /// Match at the default semantic level of a string, where each matched - /// element is a `Character`. + /// Match at the character level. + /// + /// At this semantic level, each matched element is a `Character` value. + /// This is the default semantic level. public static var graphemeCluster: RegexSemanticLevel { .init(base: .graphemeCluster) } - /// Match at the semantic level of a string's `UnicodeScalarView`, where each - /// matched element is a `UnicodeScalar` value. + /// Match at the Unicode scalar level. + /// + /// At this semantic level, the string's `UnicodeScalarView` is used for matching, + /// and each matched element is a `UnicodeScalar` value. public static var unicodeScalar: RegexSemanticLevel { .init(base: .unicodeScalar) } diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index c02725e33..4d0c12c1f 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -139,23 +139,30 @@ public struct _CharacterClassModel: Hashable { return result } - /// Returns an inverted character class if true is passed, otherwise the - /// same character class is returned. - func withInversion(_ invertion: Bool) -> Self { + /// Conditionally inverts a character class. + /// + /// - Parameter inversion: Indicates whether to invert the character class. + /// - Returns: The inverted character class if `inversion` is `true`; + /// otherwise, the same character class. + func withInversion(_ inversion: Bool) -> Self { var copy = self - if invertion { + if inversion { copy.isInverted.toggle() } return copy } - /// Returns the inverse character class. + /// Inverts a character class. public var inverted: Self { return withInversion(true) } - /// Returns the end of the match of this character class in `str`, if - /// it matches. + /// Returns the end of the match of this character class in the string. + /// + /// - Parameter str: The string to match against. + /// - Parameter at: The index to start matching. + /// - Parameter options: Options for the match operation. + /// - Returns: The index of the end of the match, or `nil` if there is no match. func matches(in str: String, at i: String.Index, with options: MatchingOptions) -> String.Index? { switch matchLevel { case .graphemeCluster: From 14674708c9c8aaac30f385aee61d22e9028db408 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Mon, 25 Apr 2022 18:52:54 -0600 Subject: [PATCH 114/133] Algorithm cleanup (#351) * Extension collection * Break out long excerpts * cleanup * bidi split * mystery mark * Update Documentation/Evolution/StringProcessingAlgorithms.md Co-authored-by: Nate Cook * split preserving Co-authored-by: Nate Cook --- .../Evolution/StringProcessingAlgorithms.md | 452 ++++++++++++------ 1 file changed, 308 insertions(+), 144 deletions(-) diff --git a/Documentation/Evolution/StringProcessingAlgorithms.md b/Documentation/Evolution/StringProcessingAlgorithms.md index eee05e3a7..001ce1fec 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -31,7 +31,7 @@ while let r = str.range(of: "banana", options: [], range: idx.. @@ -133,13 +133,13 @@ Parsing a currency string such as `$3,020.85` with regex is also tricky, as it c ### Complex string processing We propose a `CustomConsumingRegexComponent` protocol which allows types from outside the standard library participate in regex builders and `RegexComponent` algorithms. This allows types, such as `Date.ParseStrategy` and `FloatingPointFormatStyle.Currency`, to be used directly within a regex: - + ```swift let dateRegex = Regex { Capture(dateParser) } -let date: Date = header.firstMatch(of: dateRegex).map(\.result.1) +let date: Date = header.firstMatch(of: dateRegex).map(\.result.1) let currencyRegex = Regex { Capture(.localizedCurrency(code: "USD").sign(strategy: .accounting)) @@ -174,7 +174,7 @@ We also propose the following regex-powered algorithms as well as their generic `CustomConsumingRegexComponent` inherits from `RegexComponent` and satisfies its sole requirement. Conformers can be used with all of the string algorithms generic over `RegexComponent`. ```swift -/// A protocol allowing custom types to function as regex components by +/// A protocol allowing custom types to function as regex components by /// providing the raw functionality backing `prefixMatch`. public protocol CustomConsumingRegexComponent: RegexComponent { /// Process the input string within the specified bounds, beginning at the given index, and return @@ -199,7 +199,7 @@ public protocol CustomConsumingRegexComponent: RegexComponent { We use Foundation `FloatingPointFormatStyle.Currency` as an example for protocol conformance. It would implement the `match` function with `Match` being a `Decimal`. It could also add a static function `.localizedCurrency(code:)` as a member of `RegexComponent`, so it can be referred as `.localizedCurrency(code:)` in the `Regex` result builder: ```swift -extension FloatingPointFormatStyle.Currency : CustomConsumingRegexComponent { +extension FloatingPointFormatStyle.Currency : CustomConsumingRegexComponent { public func consuming( _ input: String, startingAt index: String.Index, @@ -223,10 +223,12 @@ let regex = Regex { -### String algorithm additions +### String and Collection algorithm additions #### Contains +We propose a `contains` variant over collections that tests for subsequence membership. The second algorithm allows for specialization using e.g. the [two way search algorithm](https://en.wikipedia.org/wiki/Two-way_string-matching_algorithm). + ```swift extension Collection where Element: Equatable { /// Returns a Boolean value indicating whether the collection contains the @@ -237,15 +239,31 @@ extension Collection where Element: Equatable { public func contains(_ other: C) -> Bool where S.Element == Element } +extension BidirectionalCollection where Element: Comparable { + /// Returns a Boolean value indicating whether the collection contains the + /// given sequence. + /// - Parameter other: A sequence to search for within this collection. + /// - Returns: `true` if the collection contains the specified sequence, + /// otherwise `false`. + public func contains(_ other: C) -> Bool + where S.Element == Element +} +``` -extension BidirectionalCollection where SubSequence == Substring { +We propose a regex-taking variant over string types (those that produce a `Substring` upon slicing). + +```swift +extension Collection where SubSequence == Substring { /// Returns a Boolean value indicating whether the collection contains the /// given regex. /// - Parameter regex: A regex to search for within this collection. /// - Returns: `true` if the regex was found in the collection, otherwise /// `false`. public func contains(_ regex: some RegexComponent) -> Bool +} +// In RegexBuilder module +extension Collection where SubSequence == Substring { /// Returns a Boolean value indicating whether this collection contains a /// match for the regex, where the regex is created by the given closure. /// @@ -261,15 +279,20 @@ extension BidirectionalCollection where SubSequence == Substring { #### Starts with +We propose a regex-taking `starts(with:)` variant for string types: + ```swift -extension BidirectionalCollection where SubSequence == Substring { +extension Collection where SubSequence == Substring { /// Returns a Boolean value indicating whether the initial elements of the /// sequence are the same as the elements in the specified regex. /// - Parameter regex: A regex to compare to this sequence. /// - Returns: `true` if the initial elements of the sequence matches the /// beginning of `regex`; otherwise, `false`. public func starts(with regex: some RegexComponent) -> Bool - +} + +// In RegexBuilder module +extension Collection where SubSequence == Substring { /// Returns a Boolean value indicating whether the initial elements of this /// collection are a match for the regex created by the given closure. /// @@ -285,6 +308,8 @@ extension BidirectionalCollection where SubSequence == Substring { #### Trim prefix +We propose generic `trimmingPrefix` and `trimPrefix` methods for collections that trim elements matching a predicate or a possible prefix sequence. + ```swift extension Collection { /// Returns a new collection of the same type by removing initial elements @@ -338,15 +363,22 @@ extension RangeReplaceableCollection where Element: Equatable { public mutating func trimPrefix(_ prefix: Prefix) where Prefix.Element == Element } +``` + +We propose regex-taking variants for string types: -extension BidirectionalCollection where SubSequence == Substring { +```swift +extension Collection where SubSequence == Substring { /// Returns a new subsequence by removing the initial elements that matches /// the given regex. /// - Parameter regex: The regex to remove from this collection. /// - Returns: A new subsequence containing the elements of the collection /// that does not match `prefix` from the start. public func trimmingPrefix(_ regex: some RegexComponent) -> SubSequence - +} + +// In RegexBuilder module +extension Collection where SubSequence == Substring { /// Returns a subsequence of this collection by removing the elements /// matching the regex from the start, where the regex is created by /// the given closure. @@ -362,13 +394,14 @@ extension BidirectionalCollection where SubSequence == Substring { ) -> SubSequence } -extension RangeReplaceableCollection - where Self: BidirectionalCollection, SubSequence == Substring -{ +extension RangeReplaceableCollection where SubSequence == Substring { /// Removes the initial elements that matches the given regex. /// - Parameter regex: The regex to remove from this collection. public mutating func trimPrefix(_ regex: some RegexComponent) - +} + +// In RegexBuilder module +extension RangeReplaceableCollection where SubSequence == Substring { /// Removes the initial elements matching the regex from the start of /// this collection, if the initial elements match, using the given closure /// to create the regex. @@ -383,6 +416,8 @@ extension RangeReplaceableCollection #### First range +We propose a generic collection algorithm for finding the first range of a given subsequence: + ```swift extension Collection where Element: Equatable { /// Finds and returns the range of the first occurrence of a given sequence @@ -390,7 +425,7 @@ extension Collection where Element: Equatable { /// - Parameter sequence: The sequence to search for. /// - Returns: A range in the collection of the first occurrence of `sequence`. /// Returns nil if `sequence` is not found. - public func firstRange(of other: C) -> Range? + public func firstRange(of other: C) -> Range? where C.Element == Element } @@ -403,15 +438,22 @@ extension BidirectionalCollection where Element: Comparable { public func firstRange(of other: C) -> Range? where C.Element == Element } +``` + +We propose a regex-taking variant for string types. -extension BidirectionalCollection where SubSequence == Substring { +```swift +extension Collection where SubSequence == Substring { /// Finds and returns the range of the first occurrence of a given regex /// within the collection. /// - Parameter regex: The regex to search for. /// - Returns: A range in the collection of the first occurrence of `regex`. /// Returns `nil` if `regex` is not found. public func firstRange(of regex: some RegexComponent) -> Range? - +} + +// In RegexBuilder module +extension Collection where SubSequence == Substring { /// Returns the range of the first match for the regex within this collection, /// where the regex is created by the given closure. /// @@ -421,12 +463,14 @@ extension BidirectionalCollection where SubSequence == Substring { /// for the regex is found. public func firstRange( @RegexComponentBuilder of content: () -> some RegexComponent - ) -> Range? + ) -> Range? } ``` #### Ranges +We propose a generic collection algorithm for iterating over all (non-overlapping) ranges of a given subsequence. + ```swift extension Collection where Element: Equatable { /// Finds and returns the ranges of the all occurrences of a given sequence @@ -438,14 +482,31 @@ extension Collection where Element: Equatable { where C.Element == Element } -extension BidirectionalCollection where SubSequence == Substring { +extension BidirectionalCollection where Element: Comparable { + /// Finds and returns the ranges of the all occurrences of a given sequence + /// within the collection. + /// - Parameter other: The sequence to search for. + /// - Returns: A collection of ranges of all occurrences of `other`. Returns + /// an empty collection if `other` is not found. + public func ranges(of other: C) -> some Collection> + where C.Element == Element +} +``` + +And of course regex-taking versions for string types: + +```swift +extension Collection where SubSequence == Substring { /// Finds and returns the ranges of the all occurrences of a given sequence /// within the collection. /// - Parameter regex: The regex to search for. /// - Returns: A collection or ranges in the receiver of all occurrences of /// `regex`. Returns an empty collection if `regex` is not found. public func ranges(of regex: some RegexComponent) -> some Collection> - +} + +// In RegexBuilder module +extension Collection where SubSequence == Substring { /// Returns the ranges of the all non-overlapping matches for the regex /// within this collection, where the regex is created by the given closure. /// @@ -461,14 +522,29 @@ extension BidirectionalCollection where SubSequence == Substring { #### Match +We propose algorithms for extracting a `Match` instance from a given regex from the start, anywhere in the middle, or over the entire `self`. + ```swift -extension BidirectionalCollection where SubSequence == Substring { +extension Collection where SubSequence == Substring { /// Returns the first match of the specified regex within the collection. /// - Parameter regex: The regex to search for. /// - Returns: The first match of `regex` in the collection, or `nil` if /// there isn't a match. public func firstMatch(of regex: R) -> Regex.Match? - + + /// Match a regex in its entirety. + /// - Parameter regex: The regex to match against. + /// - Returns: The match if there is one, or `nil` if none. + public func wholeMatch(of regex: R) -> Regex.Match? + + /// Match part of the regex, starting at the beginning. + /// - Parameter regex: The regex to match against. + /// - Returns: The match if there is one, or `nil` if none. + public func prefixMatch(of regex: R) -> Regex.Match? +} + +// In RegexBuilder module +extension Collection where SubSequence == Substring { /// Returns the first match for the regex within this collection, where /// the regex is created by the given closure. /// @@ -477,13 +553,8 @@ extension BidirectionalCollection where SubSequence == Substring { /// collection, or `nil` if no match is found. public func firstMatch( @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? - - /// Match a regex in its entirety. - /// - Parameter regex: The regex to match against. - /// - Returns: The match if there is one, or `nil` if none. - public func wholeMatch(of regex: R) -> Regex.Match? - + ) -> Regex.Match? + /// Matches a regex in its entirety, where the regex is created by /// the given closure. /// @@ -491,13 +562,8 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: The match if there is one, or `nil` if none. public func wholeMatch( @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? - - /// Match part of the regex, starting at the beginning. - /// - Parameter regex: The regex to match against. - /// - Returns: The match if there is one, or `nil` if none. - public func prefixMatch(of regex: R) -> Regex.Match? - + ) -> Regex.Match? + /// Matches part of the regex, starting at the beginning, where the regex /// is created by the given closure. /// @@ -511,13 +577,18 @@ extension BidirectionalCollection where SubSequence == Substring { #### Matches +We propose an algorithm for iterating over all (non-overlapping) matches of a given regex: + ```swift -extension BidirectionalCollection where SubSequence == Substring { +extension Collection where SubSequence == Substring { /// Returns a collection containing all matches of the specified regex. /// - Parameter regex: The regex to search for. /// - Returns: A collection of matches of `regex`. public func matches(of regex: R) -> some Collection.Match> - +} + +// In RegexBuilder module +extension Collection where SubSequence == Substring { /// Returns a collection containing all non-overlapping matches of /// the regex, created by the given closure. /// @@ -532,6 +603,8 @@ extension BidirectionalCollection where SubSequence == Substring { #### Replace +We propose generic collection algorithms that will replace all occurences of a given subsequence: + ```swift extension RangeReplaceableCollection where Element: Equatable { /// Returns a new collection in which all occurrences of a target sequence @@ -543,14 +616,59 @@ extension RangeReplaceableCollection where Element: Equatable { /// - maxReplacements: A number specifying how many occurrences of `other` /// to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of `other` in - /// `subrange` of the collection are replaced by `replacement`. + /// `subrange` of the collection are replaced by `replacement`. + public func replacing( + _ other: C, + with replacement: Replacement, + subrange: Range, + maxReplacements: Int = .max + ) -> Self where C.Element == Element, Replacement.Element == Element + + /// Returns a new collection in which all occurrences of a target sequence + /// are replaced by another collection. + /// - Parameters: + /// - other: The sequence to replace. + /// - replacement: The new elements to add to the collection. + /// - maxReplacements: A number specifying how many occurrences of `other` + /// to replace. Default is `Int.max`. + /// - Returns: A new collection in which all occurrences of `other` in + /// `subrange` of the collection are replaced by `replacement`. + public func replacing( + _ other: C, + with replacement: Replacement, + maxReplacements: Int = .max + ) -> Self where C.Element == Element, Replacement.Element == Element + + /// Replaces all occurrences of a target sequence with a given collection + /// - Parameters: + /// - other: The sequence to replace. + /// - replacement: The new elements to add to the collection. + /// - maxReplacements: A number specifying how many occurrences of `other` + /// to replace. Default is `Int.max`. + public mutating func replace( + _ other: C, + with replacement: Replacement, + maxReplacements: Int = .max + ) where C.Element == Element, Replacement.Element == Element +} +extension RangeReplaceableCollection where Self: BidirectionalCollection, Element: Comparable { + /// Returns a new collection in which all occurrences of a target sequence + /// are replaced by another collection. + /// - Parameters: + /// - other: The sequence to replace. + /// - replacement: The new elements to add to the collection. + /// - subrange: The range in the collection in which to search for `other`. + /// - maxReplacements: A number specifying how many occurrences of `other` + /// to replace. Default is `Int.max`. + /// - Returns: A new collection in which all occurrences of `other` in + /// `subrange` of the collection are replaced by `replacement`. public func replacing( _ other: C, with replacement: Replacement, subrange: Range, maxReplacements: Int = .max ) -> Self where C.Element == Element, Replacement.Element == Element - + /// Returns a new collection in which all occurrences of a target sequence /// are replaced by another collection. /// - Parameters: @@ -565,7 +683,7 @@ extension RangeReplaceableCollection where Element: Equatable { with replacement: Replacement, maxReplacements: Int = .max ) -> Self where C.Element == Element, Replacement.Element == Element - + /// Replaces all occurrences of a target sequence with a given collection /// - Parameters: /// - other: The sequence to replace. @@ -578,7 +696,11 @@ extension RangeReplaceableCollection where Element: Equatable { maxReplacements: Int = .max ) where C.Element == Element, Replacement.Element == Element } +``` + +We propose regex-taking variants for string types as well as variants that take a closure which will generate the replacement portion from a regex match (e.g. by reading captures). +```swift extension RangeReplaceableCollection where SubSequence == Substring { /// Returns a new collection in which all occurrences of a sequence matching /// the given regex are replaced by another collection. @@ -597,6 +719,85 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: Int = .max ) -> Self where Replacement.Element == Element + /// Returns a new collection in which all occurrences of a sequence matching + /// the given regex are replaced by another collection. + /// - Parameters: + /// - regex: A regex describing the sequence to replace. + /// - replacement: The new elements to add to the collection. + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - Returns: A new collection in which all occurrences of subsequence + /// matching `regex` are replaced by `replacement`. + public func replacing( + _ r: some RegexComponent, + with replacement: Replacement, + maxReplacements: Int = .max + ) -> Self where Replacement.Element == Element + + /// Replaces all occurrences of the sequence matching the given regex with + /// a given collection. + /// - Parameters: + /// - regex: A regex describing the sequence to replace. + /// - replacement: The new elements to add to the collection. + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + public mutating func replace( + _ r: some RegexComponent, + with replacement: Replacement, + maxReplacements: Int = .max + ) where Replacement.Element == Element + + /// Returns a new collection in which all occurrences of a sequence matching + /// the given regex are replaced by another regex match. + /// - Parameters: + /// - regex: A regex describing the sequence to replace. + /// - subrange: The range in the collection in which to search for `regex`. + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. + /// - Returns: A new collection in which all occurrences of subsequence + /// matching `regex` are replaced by `replacement`. + public func replacing( + _ regex: R, + subrange: Range, + maxReplacements: Int = .max, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows -> Self where Replacement.Element == Element + + /// Returns a new collection in which all occurrences of a sequence matching + /// the given regex are replaced by another collection. + /// - Parameters: + /// - regex: A regex describing the sequence to replace. + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. + /// - Returns: A new collection in which all occurrences of subsequence + /// matching `regex` are replaced by `replacement`. + public func replacing( + _ regex: R, + maxReplacements: Int = .max, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows -> Self where Replacement.Element == Element + + /// Replaces all occurrences of the sequence matching the given regex with + /// a given collection. + /// - Parameters: + /// - regex: A regex describing the sequence to replace. + /// - maxReplacements: A number specifying how many occurrences of the + /// sequence matching `regex` to replace. Default is `Int.max`. + /// - replacement: A closure that receives the full match information, + /// including captures, and returns a replacement collection. + public mutating func replace( + _ regex: R, + maxReplacements: Int = .max, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows where Replacement.Element == Element +} + +// In RegexBuilder module +extension Collection where SubSequence == Substring { /// Returns a new collection in which all matches for the regex /// are replaced, using the given closure to create the regex. /// @@ -610,29 +811,14 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - content: A closure that returns the collection to search for /// and replace. /// - Returns: A new collection in which all matches for regex in `subrange` - /// are replaced by `replacement`, using `content` to create the regex. + /// are replaced by `replacement`, using `content` to create the regex. public func replacing( with replacement: Replacement, subrange: Range, maxReplacements: Int = .max, @RegexComponentBuilder content: () -> some RegexComponent ) -> Self where Replacement.Element == Element - - /// Returns a new collection in which all occurrences of a sequence matching - /// the given regex are replaced by another collection. - /// - Parameters: - /// - regex: A regex describing the sequence to replace. - /// - replacement: The new elements to add to the collection. - /// - maxReplacements: A number specifying how many occurrences of the - /// sequence matching `regex` to replace. Default is `Int.max`. - /// - Returns: A new collection in which all occurrences of subsequence - /// matching `regex` are replaced by `replacement`. - public func replacing( - _ r: some RegexComponent, - with replacement: Replacement, - maxReplacements: Int = .max - ) -> Self where Replacement.Element == Element - + /// Returns a new collection in which all matches for the regex /// are replaced, using the given closure to create the regex. /// @@ -649,21 +835,8 @@ extension RangeReplaceableCollection where SubSequence == Substring { with replacement: Replacement, maxReplacements: Int = .max, @RegexComponentBuilder content: () -> some RegexComponent - ) -> Self where Replacement.Element == Element - - /// Replaces all occurrences of the sequence matching the given regex with - /// a given collection. - /// - Parameters: - /// - regex: A regex describing the sequence to replace. - /// - replacement: The new elements to add to the collection. - /// - maxReplacements: A number specifying how many occurrences of the - /// sequence matching `regex` to replace. Default is `Int.max`. - public mutating func replace( - _ r: some RegexComponent, - with replacement: Replacement, - maxReplacements: Int = .max - ) where Replacement.Element == Element - + ) -> Self where Replacement.Element == Element + /// Replaces all matches for the regex in this collection, using the given /// closure to create the regex. /// @@ -678,25 +851,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { with replacement: Replacement, maxReplacements: Int = .max, @RegexComponentBuilder content: () -> some RegexComponent - ) where Replacement.Element == Element - - /// Returns a new collection in which all occurrences of a sequence matching - /// the given regex are replaced by another regex match. - /// - Parameters: - /// - regex: A regex describing the sequence to replace. - /// - subrange: The range in the collection in which to search for `regex`. - /// - maxReplacements: A number specifying how many occurrences of the - /// sequence matching `regex` to replace. Default is `Int.max`. - /// - replacement: A closure that receives the full match information, - /// including captures, and returns a replacement collection. - /// - Returns: A new collection in which all occurrences of subsequence - /// matching `regex` are replaced by `replacement`. - public func replacing( - _ regex: R, - subrange: Range, - maxReplacements: Int = .max, - with replacement: (Regex.Match) throws -> Replacement - ) rethrows -> Self where Replacement.Element == Element + ) where Replacement.Element == Element /// Returns a new collection in which all matches for the regex /// are replaced, using the given closures to create the replacement @@ -720,23 +875,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { @RegexComponentBuilder content: () -> R, with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element - - /// Returns a new collection in which all occurrences of a sequence matching - /// the given regex are replaced by another collection. - /// - Parameters: - /// - regex: A regex describing the sequence to replace. - /// - maxReplacements: A number specifying how many occurrences of the - /// sequence matching `regex` to replace. Default is `Int.max`. - /// - replacement: A closure that receives the full match information, - /// including captures, and returns a replacement collection. - /// - Returns: A new collection in which all occurrences of subsequence - /// matching `regex` are replaced by `replacement`. - public func replacing( - _ regex: R, - maxReplacements: Int = .max, - with replacement: (Regex.Match) throws -> Replacement - ) rethrows -> Self where Replacement.Element == Element - + /// Returns a new collection in which all matches for the regex /// are replaced, using the given closures to create the replacement /// and the regex. @@ -756,20 +895,6 @@ extension RangeReplaceableCollection where SubSequence == Substring { @RegexComponentBuilder content: () -> R, with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element - - /// Replaces all occurrences of the sequence matching the given regex with - /// a given collection. - /// - Parameters: - /// - regex: A regex describing the sequence to replace. - /// - maxReplacements: A number specifying how many occurrences of the - /// sequence matching `regex` to replace. Default is `Int.max`. - /// - replacement: A closure that receives the full match information, - /// including captures, and returns a replacement collection. - public mutating func replace( - _ regex: R, - maxReplacements: Int = .max, - with replacement: (Regex.Match) throws -> Replacement - ) rethrows where Replacement.Element == Element /// Replaces all matches for the regex in this collection, using the /// given closures to create the replacement and the regex. @@ -791,6 +916,8 @@ extension RangeReplaceableCollection where SubSequence == Substring { #### Split +We propose a generic collection `split` that can take a subsequence separator: + ```swift extension Collection where Element: Equatable { /// Returns the longest possible subsequences of the collection, in order, @@ -798,11 +925,11 @@ extension Collection where Element: Equatable { /// /// - Parameters: /// - separator: A collection of elements to be split upon. - /// - maxSplits: The maximum number of times to split the collection, + /// - maxSplits: The maximum number of times to split the collection, /// or one less than the number of subsequences to return. - /// - omittingEmptySubsequences: If `false`, an empty subsequence is - /// returned in the result for each consecutive pair of separator - /// sequences in the collection and for each instance of separator + /// - omittingEmptySubsequences: If `false`, an empty subsequence is + /// returned in the result for each consecutive pair of separator + /// sequences in the collection and for each instance of separator /// sequences at the start or end of the collection. If `true`, only /// nonempty subsequences are returned. /// - Returns: A collection of subsequences, split from this collection's @@ -813,16 +940,41 @@ extension Collection where Element: Equatable { omittingEmptySubsequences: Bool = true ) -> some Collection where C.Element == Element } +extension BidirectionalCollection where Element: Comparable { + /// Returns the longest possible subsequences of the collection, in order, + /// around elements equal to the given separator collection. + /// + /// - Parameters: + /// - separator: A collection of elements to be split upon. + /// - maxSplits: The maximum number of times to split the collection, + /// or one less than the number of subsequences to return. + /// - omittingEmptySubsequences: If `false`, an empty subsequence is + /// returned in the result for each consecutive pair of separator + /// sequences in the collection and for each instance of separator + /// sequences at the start or end of the collection. If `true`, only + /// nonempty subsequences are returned. + /// - Returns: A collection of subsequences, split from this collection's + /// elements. + public func split( + separator: C, + maxSplits: Int = Int.max, + omittingEmptySubsequences: Bool = true + ) -> some Collection where C.Element == Element +} +``` -extension BidirectionalCollection where SubSequence == Substring { +And a regex-taking variant for string types: + +```swift +extension Collection where SubSequence == Substring { /// Returns the longest possible subsequences of the collection, in order, /// around subsequence that match the given separator regex. /// /// - Parameters: /// - separator: A regex to be split upon. - /// - maxSplits: The maximum number of times to split the collection, + /// - maxSplits: The maximum number of times to split the collection, /// or one less than the number of subsequences to return. - /// - omittingEmptySubsequences: If `false`, an empty subsequence is + /// - omittingEmptySubsequences: If `false`, an empty subsequence is /// returned in the result for each consecutive pair of matches /// and for each match at the start or end of the collection. If /// `true`, only nonempty subsequences are returned. @@ -833,7 +985,10 @@ extension BidirectionalCollection where SubSequence == Substring { maxSplits: Int = Int.max, omittingEmptySubsequences: Bool = true ) -> some Collection - +} + +// In RegexBuilder module +extension Collection where SubSequence == Substring { /// Returns the longest possible subsequences of the collection, in order, /// around subsequence that match the regex created by the given closure. /// @@ -918,24 +1073,33 @@ Older versions of the pitch had `func match(...) -> (String.Index, T)?` as the p This protocol customizes the basic consume-from-the-front functionality. A protocol for customizing search is future work and involves accommodating different kinds of state and ways that a searcher may wish to speed up subsequent searches. Alternative names for the protocol include `CustomRegexComponent`, `CustomConsumingRegex`, etc., but we don't feel brevity is the key consideration here. +### Why `where SubSequence == Substring`? + +A `Substring` slice requirement allows the regex engine to produce indicies in the original collection by operating over a portion of the input. Unfortunately, this is not one of the requirements of `StringProtocol`. + +A new protocol for types that can produce a `Substring` on request (e.g. from UTF-8 contents) would have to eagerly produce a `String` copy first and would need requirements to translate indices. When higher-level algorithms are implemented via multiple calls to the lower-level algorithms, these copies could happen many times. Shared strings are future work but a much better solution to this. + ## Future directions ### Backward algorithms -It would be useful to have algorithms that operate from the back of a collection, including ability to find the last non-overlapping range of a pattern in a string, and/or that to find the first range of a pattern when searching from the back, and trimming a string from both sides. They are deferred from this proposal as the API that could clarify the nuances of backward algorithms are still being explored. +It would be useful to have algorithms that operate from the back of a collection, including ability to find the last non-overlapping range of a pattern in a string, and/or that to find the first range of a pattern when searching from the back, and trimming a string from both sides. They are deferred from this proposal as the API that could clarify the nuances of backward algorithms are still being explored.
Nuances of backward algorithms -There is a subtle difference between finding the last non-overlapping range of a pattern in a string, and finding the first range of this pattern when searching from the back. +There is a subtle difference between finding the last non-overlapping range of a pattern in a string, and finding the first range of this pattern when searching from the back. -The currently proposed algorithm that finds a pattern from the front, e.g. `"aaaaa".ranges(of: "aa")`, produces two non-overlapping ranges, splitting the string in the chunks `aa|aa|a`. It would not be completely unreasonable to expect to introduce a counterpart, such as `"aaaaa".lastRange(of: "aa")`, to return the range that contains the third and fourth characters of the string. This would be a shorthand for `"aaaaa".ranges(of: "aa").last`. Yet, it would also be reasonable to expect the function to return the first range of `"aa"` when searching from the back of the string, i.e. the range that contains the fourth and fifth characters. +The currently proposed algorithm that finds a pattern from the front, e.g. `"aaaaa".ranges(of: "aa")`, produces two non-overlapping ranges, splitting the string in the chunks `aa|aa|a`. It would not be completely unreasonable to expect to introduce a counterpart, such as `"aaaaa".lastRange(of: "aa")`, to return the range that contains the third and fourth characters of the string. This would be a shorthand for `"aaaaa".ranges(of: "aa").last`. Yet, it would also be reasonable to expect the function to return the first range of `"aa"` when searching from the back of the string, i.e. the range that contains the fourth and fifth characters. -Trimming a string from both sides shares a similar story. For example, `"ababa".trimming("aba")` can return either `"ba"` or `"ab"`, depending on whether the prefix or the suffix was trimmed first. +Trimming a string from both sides shares a similar story. For example, `"ababa".trimming("aba")` can return either `"ba"` or `"ab"`, depending on whether the prefix or the suffix was trimmed first.
- +### Split preserving the separator + +Future work is a split variant that interweaves the separator with the separated portions. For example, when splitting over `\p{punctuation}` it might be useful to be able to preserve the punctionation as a separate entry in the returned collection. + ### Future API -Some common string processing functions are not currently included in this proposal, such as trimming the suffix from a string/collection, and finding overlapping ranges of matched substrings. This pitch aims to establish a pattern for using `RegexComponent` with string processing algorithms, so that further enhancement can to be introduced to the standard library easily in the future, and eventually close the gap between Swift and other popular scripting languages. +Some common string processing functions are not currently included in this proposal, such as trimming the suffix from a string/collection, and finding overlapping ranges of matched substrings. This pitch aims to establish a pattern for using `RegexComponent` with string processing algorithms, so that further enhancement can to be introduced to the standard library easily in the future, and eventually close the gap between Swift and other popular scripting languages. From e0922ec2c947c6955eb621455ced1718f5d59eff Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Mon, 25 Apr 2022 19:46:24 -0600 Subject: [PATCH 115/133] API stubs for casting and named captures (#349) * API stubs for casting and named captures * Update Sources/_StringProcessing/Regex/AnyRegexOutput.swift Co-authored-by: Richard Wei Co-authored-by: Richard Wei --- .../Regex/AnyRegexOutput.swift | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift index 0d018aa81..295ef97fc 100644 --- a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift +++ b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift @@ -205,3 +205,28 @@ extension Regex.Match where Output == AnyRegexOutput { fatalError("FIXME: Not implemented") } } + +@available(SwiftStdlib 5.7, *) +extension Regex where Output == AnyRegexOutput { + /// Returns whether a named-capture with `name` exists + public func contains(captureNamed name: String) -> Bool { + fatalError("FIXME: not implemented") + } + + /// Creates a type-erased regex from an existing regex. + /// + /// Use this initializer to fit a regex with strongly typed captures into the + /// use site of a dynamic regex, i.e. one that was created from a string. + public init(_ match: Regex) { + fatalError("FIXME: Not implemented") + } + + /// Returns a typed regex by converting the underlying types. + /// + /// - Parameter type: The expected output type. + /// - Returns: A regex generic over the output type if the underlying types can be converted. + /// Returns `nil` otherwise. + public func `as`(_ type: Output.Type) -> Regex? { + fatalError("FIXME: Not implemented") + } +} From bef2092af735465fb6878427e09b04d80247b6cf Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Tue, 26 Apr 2022 07:38:50 -0600 Subject: [PATCH 116/133] Mention language level pattern matching (#354) --- .../Evolution/StringProcessingAlgorithms.md | 38 +++++++++++++++++++ Tests/RegexBuilderTests/AlgorithmsTests.swift | 3 ++ 2 files changed, 41 insertions(+) diff --git a/Documentation/Evolution/StringProcessingAlgorithms.md b/Documentation/Evolution/StringProcessingAlgorithms.md index 001ce1fec..8106281ca 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -166,6 +166,31 @@ We also propose the following regex-powered algorithms as well as their generic |`prefixMatch(of:)`| Matches the specified `RegexComponent` against the collection at the beginning | |`matches(of:)`| Returns a collection containing all matches of the specified `RegexComponent` | +We also propose an overload of `~=` allowing regexes to be used in `case` expressions: + +```swift + switch "abcde" { + case /a.*f/: // never taken + case /abc/: // never taken + case /ab.*e/: return "success" + default: // never taken + } + + switch "2022-04-22" { + case decimalParser: // never taken + + case OneOrMore { + CharacterClass.whitespace + }: // never taken + + case #/\d{2}/\d{2}/\d{4}/# // never taken + + case dateParser: return "success" + + default: // never taken + } +``` + ## Detailed design @@ -1025,6 +1050,19 @@ extension RangeReplaceableCollection where Element: Equatable { } ``` +### Language-level pattern matching via `~=` + +We propose allowing any regex component be used in case statements by overloading the `~=` operator for matching against the entire input: + +```swift +extension RegexComponent { + public static func ~=(regex: Self, input: String) -> Bool + + public static func ~=(regex: Self, input: Substring) -> Bool +} +``` + + [SE-0346]: https://github.com/apple/swift-evolution/blob/main/proposals/0346-light-weight-same-type-syntax.md [stdlib-pitch]: https://forums.swift.org/t/pitch-primary-associated-types-in-the-standard-library/56426 diff --git a/Tests/RegexBuilderTests/AlgorithmsTests.swift b/Tests/RegexBuilderTests/AlgorithmsTests.swift index 220535e31..173d41598 100644 --- a/Tests/RegexBuilderTests/AlgorithmsTests.swift +++ b/Tests/RegexBuilderTests/AlgorithmsTests.swift @@ -116,6 +116,9 @@ class RegexConsumerTests: XCTestCase { }: XCTFail() + case OneOrMore { CharacterClass.whitespace }: + XCTFail() + case "abc": XCTFail() From 9ff87db3250a6a4d7cf40e96bb58b41d46ed2495 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 26 Apr 2022 09:23:03 -0500 Subject: [PATCH 117/133] Fix empty.split w/ empty separator (#353) --- .../_StringProcessing/Algorithms/Algorithms/Split.swift | 4 ++++ Tests/RegexTests/AlgorithmsTests.swift | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift index 97d8c80dd..f7bbfbd0c 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -75,6 +75,10 @@ extension SplitCollection: Sequence { : base[index...] } + if index == base.endIndex { + return finish() + } + if splitCounter >= maxSplits { return finish() } diff --git a/Tests/RegexTests/AlgorithmsTests.swift b/Tests/RegexTests/AlgorithmsTests.swift index 965e2c42e..d63333c01 100644 --- a/Tests/RegexTests/AlgorithmsTests.swift +++ b/Tests/RegexTests/AlgorithmsTests.swift @@ -128,14 +128,17 @@ class AlgorithmTests: XCTestCase { XCTAssertEqual(actual, expected, file: file, line: line) } - expectSplit("", "", ["", ""]) + expectSplit("", "", [""]) expectSplit("", "x", [""]) expectSplit("a", "", ["", "a", ""]) expectSplit("a", "x", ["a"]) expectSplit("a", "a", ["", ""]) expectSplit("a____a____a", "_+", ["a", "a", "a"]) expectSplit("____a____a____a____", "_+", ["", "a", "a", "a", ""]) - + + XCTAssertEqual("".split(separator: ""), []) + XCTAssertEqual("".split(separator: "", omittingEmptySubsequences: false), [""]) + // Test that original `split` functions are still accessible let splitRef = "abcd".split XCTAssert(type(of: splitRef) == ((Character, Int, Bool) -> [Substring]).self) From 2401a58325385f54b4c881655d56c743723846e5 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 26 Apr 2022 09:23:20 -0500 Subject: [PATCH 118/133] Add a section describing 'find empty' behavior (#352) --- .../Evolution/StringProcessingAlgorithms.md | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/Documentation/Evolution/StringProcessingAlgorithms.md b/Documentation/Evolution/StringProcessingAlgorithms.md index 8106281ca..58426c145 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -1066,11 +1066,50 @@ extension RegexComponent { [SE-0346]: https://github.com/apple/swift-evolution/blob/main/proposals/0346-light-weight-same-type-syntax.md [stdlib-pitch]: https://forums.swift.org/t/pitch-primary-associated-types-in-the-standard-library/56426 +#### Searching for empty strings and matches + +Empty matches and inputs are an important edge case for several of the algorithms proposed above. For example, what is the result of `"123.firstRange(of: /[a-z]*/)`? How do you split a collection separated by an empty collection, as in `"1234".split(separator: "")`? For the Swift standard library, this is a new consideration, as current algorithms are `Element`-based and cannot be passed an empty input. + +Languages and libraries are nearly unanimous about finding the location of an empty string, with Ruby, Python, C#, Java, Javascript, etc, finding an empty string at each index in the target. Notably, Foundation's `NSString.range(of:)` does _not_ find an empty string at all. + +The methods proposed here follow the consensus behavior, which makes sense if you think of `a.firstRange(of: b)` as returning the first subrange `r` where `a[r] == b`. If a regex can match an empty substring, like `/[a-z]*/`, the behavior is the same. + +```swift +let hello = "Hello" +let emptyRange = hello.firstRange(of: "") +// emptyRange is equivalent to '0..<0' (integer ranges shown for readability) +``` + +Because searching again at the same index would yield that same empty string, we advance one position after finding an empty string or matching an empty pattern when finding all ranges. This yields the position of every valid index in the string. + +```swift +let allRanges = hello.ranges(of: "") +// allRanges is equivalent to '[0..<0, 1..<1, 2..<2, 3..<3, 4..<4, 5..<5]' +``` + +Splitting with an empty separator (or a pattern that matches empty string), uses this same behavior, resulting in a collection of single-element substrings. Interestingly, a couple languages make different choices here. C# returns the original string instead of its parts, and Python rejects an empty separator (though it permits regexes that match empty strings). + +```swift +let parts = hello.split(separator: "") +// parts == ["h", "e", "l", "l", "o"] + +let moreParts = hello.split(separator: "", omittingEmptySubsequences: false) +// parts == ["", "h", "e", "l", "l", "o", ""] +``` + +Finally, searching for an empty string within an empty string yields, as you might imagine, the empty string: + +```swift +let empty = "" +let range = empty.firstRange(of: empty) +// empty == empty[range] +``` + ## Alternatives considered ### Extend `Sequence` instead of `Collection` -Most of the proposed algorithms are necessarily on `Collection` due to the use of indices or mutation. `Sequence` does not support multi-pass iteration, so even `trimPrefix` would problematic on `Sequence` because it needs to look 1 `Element` ahead to know when to stop trimming. +Most of the proposed algorithms are necessarily on `Collection` due to the use of indices or mutation. `Sequence` does not support multi-pass iteration, so even `trimmingPrefix` would problematic on `Sequence` because it needs to look one `Element` ahead to know when to stop trimming and would need to return a wrapper for the in-progress iterator instead of a subsequence. ### Cross-proposal API naming consistency From d0598b7f50fe7fcfb58ce47ac09582e1bf632d8f Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 26 Apr 2022 09:24:13 -0500 Subject: [PATCH 119/133] Add example from RegexBuilder proposal as a test (#344) The "motivation tests" still aren't working on macOS CI --- Tests/RegexBuilderTests/MotivationTests.swift | 135 +++++++++++++++--- Tests/RegexBuilderTests/RegexDSLTests.swift | 32 +++++ 2 files changed, 145 insertions(+), 22 deletions(-) diff --git a/Tests/RegexBuilderTests/MotivationTests.swift b/Tests/RegexBuilderTests/MotivationTests.swift index 22e790e2d..7dd4c77e4 100644 --- a/Tests/RegexBuilderTests/MotivationTests.swift +++ b/Tests/RegexBuilderTests/MotivationTests.swift @@ -9,18 +9,14 @@ // //===----------------------------------------------------------------------===// -// FIXME: macOS CI seems to be busted and Linux doesn't have FormatStyle -// So, we disable this file for now - -#if false - -import _MatchingEngine - import XCTest import _StringProcessing - import RegexBuilder +// FIXME: macOS CI seems to be busted and Linux doesn't have FormatStyle +// So, we disable this larger test for now. +#if false + private struct Transaction: Hashable { enum Kind: Hashable { case credit @@ -140,17 +136,19 @@ private func processWithRuntimeDynamicRegex( ) -> Transaction? { // FIXME: Shouldn't this init throw? let regex = try! Regex(pattern) + let dateStrat = Date.FormatStyle(date: .numeric).parseStrategy + + guard let result = line.wholeMatch(of: regex)?.output, + let kind = Transaction.Kind(result[1].substring!), + let date = try? Date(String(result[2].substring!), strategy: dateStrat), + let account = result[3].substring.map(String.init), + let amount = try? Decimal( + String(result[4].substring!), format: .currency(code: "USD")) else { + return nil + } -// guard let result = line.match(regex) else { return nil } -// -// // TODO: We should have Regex or somesuch and `.1` -// // should be the same as `\1`. -// let dynCaps = result.1 -// -// -// let kind = Transaction.Kind(result.1.first!.capture as Substring) - - return nil + return Transaction( + kind: kind, date: date, account: account, amount: amount) } @available(macOS 12.0, *) @@ -239,7 +237,8 @@ extension RegexDSLTests { XCTAssertEqual( referenceOutput, processWithNSRegularExpression(line)) - _ = processWithRuntimeDynamicRegex(line) + XCTAssertEqual( + referenceOutput, processWithRuntimeDynamicRegex(line)) // Static run-time regex XCTAssertEqual( @@ -256,12 +255,104 @@ extension RegexDSLTests { XCTFail() continue } - } - } - } #endif +extension RegexDSLTests { + func testProposalExample() { + let statement = """ + CREDIT 04062020 PayPal transfer $4.99 + CREDIT 04032020 Payroll $69.73 + DEBIT 04022020 ACH transfer $38.25 + DEBIT 03242020 IRS tax payment $52249.98 + """ + let expectation: [(TransactionKind, Date, Substring, Double)] = [ + (.credit, Date(mmddyyyy: "04062020")!, "PayPal transfer", 4.99), + (.credit, Date(mmddyyyy: "04032020")!, "Payroll", 69.73), + (.debit, Date(mmddyyyy: "04022020")!, "ACH transfer", 38.25), + (.debit, Date(mmddyyyy: "03242020")!, "IRS tax payment", 52249.98), + ] + + enum TransactionKind: String { + case credit = "CREDIT" + case debit = "DEBIT" + } + + struct Date: Hashable { + var month: Int + var day: Int + var year: Int + + init?(mmddyyyy: String) { + guard let (_, m, d, y) = mmddyyyy.wholeMatch(of: Regex { + Capture(Repeat(.digit, count: 2), transform: { Int($0)! }) + Capture(Repeat(.digit, count: 2), transform: { Int($0)! }) + Capture(Repeat(.digit, count: 4), transform: { Int($0)! }) + })?.output else { + return nil + } + + self.month = m + self.day = d + self.year = y + } + } + + let statementRegex = Regex { + // First, lets capture the transaction kind by wrapping our ChoiceOf in a + // TryCapture because we want + TryCapture { + ChoiceOf { + "CREDIT" + "DEBIT" + } + } transform: { + TransactionKind(rawValue: String($0)) + } + + OneOrMore(.whitespace) + + // Next, lets represent our date as 3 separate repeat quantifiers. The first + // two will require 2 digit characters, and the last will require 4. Then + // we'll take the entire substring and try to parse a date out. + TryCapture { + Repeat(.digit, count: 2) + Repeat(.digit, count: 2) + Repeat(.digit, count: 4) + } transform: { + Date(mmddyyyy: String($0)) + } + + OneOrMore(.whitespace) + + // Next, grab the description which can be any combination of word characters, + // digits, etc. + Capture { + OneOrMore(.any, .reluctant) + } + + OneOrMore(.whitespace) + + "$" + + // Finally, we'll grab one or more digits which will represent the whole + // dollars, match the decimal point, and finally get 2 digits which will be + // our cents. + TryCapture { + OneOrMore(.digit) + "." + Repeat(.digit, count: 2) + } transform: { + Double($0) + } + } + + for (i, match) in statement.matches(of: statementRegex).enumerated() { + let (_, kind, date, description, amount) = match.output + XCTAssert((kind, date, description, amount) == expectation[i]) + } + } +} diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 42cb9c52e..b646f16f7 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -830,6 +830,38 @@ class RegexDSLTests: XCTestCase { XCTAssertEqual(result[b], 42) } + do { + let key = Reference(Substring.self) + let value = Reference(Int.self) + let input = " " + let regex = Regex { + Capture(as: key) { + Optionally { + OneOrMore(.word) + } + } + ":" + Optionally { + Capture(as: value) { + OneOrMore(.digit) + } transform: { Int($0)! } + } + } + + let result1 = try XCTUnwrap("age:123".wholeMatch(of: regex)) + XCTAssertEqual(result1[key], "age") + XCTAssertEqual(result1[value], 123) + + let result2 = try XCTUnwrap(":567".wholeMatch(of: regex)) + XCTAssertEqual(result2[key], "") + XCTAssertEqual(result2[value], 567) + + let result3 = try XCTUnwrap("status:".wholeMatch(of: regex)) + XCTAssertEqual(result3[key], "status") + // Traps: + // XCTAssertEqual(result3[value], nil) + } + // Post-hoc captured references // #"(?:\w\1|:(\w):)+"# try _testDSLCaptures( From 435090d1d13f08db1b88f5d2c909ed2b9a5b7061 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Tue, 26 Apr 2022 13:37:21 -0600 Subject: [PATCH 120/133] Refactor generator script (#356) * Number captures consistently * Proper indentation --- Sources/RegexBuilder/Variadics.swift | 1623 +++++++---------- .../VariadicsGenerator.swift | 123 +- Tests/RegexTests/MatchTests.swift | 1 + 3 files changed, 675 insertions(+), 1072 deletions(-) diff --git a/Sources/RegexBuilder/Variadics.swift b/Sources/RegexBuilder/Variadics.swift index 356853ec5..f06978c8b 100644 --- a/Sources/RegexBuilder/Variadics.swift +++ b/Sources/RegexBuilder/Variadics.swift @@ -15,496 +15,441 @@ @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0) { + ) -> Regex<(Substring, C1)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1) { + ) -> Regex<(Substring, C1, C2)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2) { + ) -> Regex<(Substring, C1, C2, C3)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3) { + ) -> Regex<(Substring, C1, C2, C3, C4)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1) { + ) -> Regex<(Substring, C1, C2)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2) { + ) -> Regex<(Substring, C1, C2, C3)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3) { + ) -> Regex<(Substring, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2) { + ) -> Regex<(Substring, C1, C2, C3)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3) { + ) -> Regex<(Substring, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8, C9, C10) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3) { + ) -> Regex<(Substring, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8, C9, C10) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8, C9, C10) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8, C9, C10) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8, C9) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8, C9, C10) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8, C9) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8, C9, C10) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6, C7, C8), R1.RegexOutput == (W1, C9) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8, C9) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6, C7, C8), R1.RegexOutput == (W1, C9, C10) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.RegexOutput == (W1, C9) { + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R1.RegexOutput == (W1, C10) { .init(node: accumulated.regex.root.appending(next.regex.root)) } } @@ -611,7 +556,6 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: Component, @@ -624,7 +568,6 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -637,7 +580,6 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) public static func buildLimitedAvailability( _ component: Component ) -> Regex { @@ -646,7 +588,6 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: Component, @@ -659,7 +600,6 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -673,7 +613,6 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: Component, @@ -686,7 +625,6 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -700,7 +638,6 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: Component, @@ -711,7 +648,6 @@ extension Repeat { self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( count: Int, @@ -722,7 +658,6 @@ extension Repeat { self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: Component, @@ -732,7 +667,6 @@ extension Repeat { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, @@ -744,11 +678,10 @@ extension Repeat { } @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } @@ -756,11 +689,10 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } @@ -768,20 +700,18 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?)> where Component.RegexOutput == (W, C0) { + ) -> Regex<(Substring, C1?)> where Component.RegexOutput == (W, C1) { .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } @@ -789,11 +719,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } @@ -802,11 +731,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, C1), Component.RegexOutput == (W, C1) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } @@ -814,11 +742,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, C1), Component.RegexOutput == (W, C1) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } @@ -827,51 +754,46 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, count: Int - ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ expression: R, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0), R.Bound == Int { + ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ expression: R, _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?), Component.RegexOutput == (W, C0), R.Bound == Int { + ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } @@ -879,11 +801,10 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } @@ -891,20 +812,18 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?)> where Component.RegexOutput == (W, C0, C1) { + ) -> Regex<(Substring, C1?, C2?)> where Component.RegexOutput == (W, C1, C2) { .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } @@ -912,11 +831,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } @@ -925,11 +843,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, C1, C2), Component.RegexOutput == (W, C1, C2) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } @@ -937,11 +854,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, C1, C2), Component.RegexOutput == (W, C1, C2) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } @@ -950,51 +866,46 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, count: Int - ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ expression: R, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ expression: R, _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?), Component.RegexOutput == (W, C0, C1), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } @@ -1002,11 +913,10 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } @@ -1014,20 +924,18 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?)> where Component.RegexOutput == (W, C0, C1, C2) { + ) -> Regex<(Substring, C1?, C2?, C3?)> where Component.RegexOutput == (W, C1, C2, C3) { .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } @@ -1035,11 +943,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } @@ -1048,11 +955,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C1, C2, C3), Component.RegexOutput == (W, C1, C2, C3) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } @@ -1060,11 +966,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C1, C2, C3), Component.RegexOutput == (W, C1, C2, C3) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } @@ -1073,51 +978,46 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, count: Int - ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ expression: R, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ expression: R, _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?), Component.RegexOutput == (W, C0, C1, C2), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } @@ -1125,11 +1025,10 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } @@ -1137,20 +1036,18 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.RegexOutput == (W, C0, C1, C2, C3) { + ) -> Regex<(Substring, C1?, C2?, C3?, C4?)> where Component.RegexOutput == (W, C1, C2, C3, C4) { .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } @@ -1158,11 +1055,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } @@ -1171,11 +1067,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C1, C2, C3, C4), Component.RegexOutput == (W, C1, C2, C3, C4) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } @@ -1183,11 +1078,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C1, C2, C3, C4), Component.RegexOutput == (W, C1, C2, C3, C4) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } @@ -1196,51 +1090,46 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, count: Int - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ expression: R, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ expression: R, _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?), Component.RegexOutput == (W, C0, C1, C2, C3), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } @@ -1248,11 +1137,10 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } @@ -1260,20 +1148,18 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?)> where Component.RegexOutput == (W, C1, C2, C3, C4, C5) { .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } @@ -1281,11 +1167,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } @@ -1294,11 +1179,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } @@ -1306,11 +1190,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } @@ -1319,51 +1202,46 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, count: Int - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ expression: R, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ expression: R, _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C0, C1, C2, C3, C4), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } @@ -1371,11 +1249,10 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } @@ -1383,20 +1260,18 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } @@ -1404,11 +1279,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } @@ -1417,11 +1291,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } @@ -1429,11 +1302,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } @@ -1442,51 +1314,46 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, count: Int - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ expression: R, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ expression: R, _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } @@ -1494,11 +1361,10 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } @@ -1506,20 +1372,18 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } @@ -1527,11 +1391,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } @@ -1540,11 +1403,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } @@ -1552,11 +1414,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } @@ -1565,51 +1426,46 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, count: Int - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ expression: R, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ expression: R, _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } @@ -1617,11 +1473,10 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } @@ -1629,20 +1484,18 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } @@ -1650,11 +1503,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } @@ -1663,11 +1515,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } @@ -1675,11 +1526,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } @@ -1688,51 +1538,46 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, count: Int - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ expression: R, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ expression: R, _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } @@ -1740,11 +1585,10 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } @@ -1752,20 +1596,18 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } @@ -1773,11 +1615,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } @@ -1786,11 +1627,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } @@ -1798,11 +1638,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } @@ -1811,51 +1650,46 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, count: Int - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ expression: R, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ expression: R, _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } @@ -1863,11 +1697,10 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } @@ -1875,20 +1708,18 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?)> where Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } @@ -1896,11 +1727,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } @@ -1909,11 +1739,10 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } @@ -1921,11 +1750,10 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } @@ -1934,41 +1762,37 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, count: Int - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component, _ expression: R, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ expression: R, _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ component: Component - ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, C1), Component.RegexOutput == (W, C1) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -2006,18 +1830,18 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0), Component.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, C1), Component.RegexOutput == (W, C1) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component - ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, C1, C2), Component.RegexOutput == (W, C1, C2) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -2025,18 +1849,18 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1), Component.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, C1, C2), Component.RegexOutput == (W, C1, C2) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component - ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C1, C2, C3), Component.RegexOutput == (W, C1, C2, C3) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -2044,18 +1868,18 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2), Component.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, C1, C2, C3), Component.RegexOutput == (W, C1, C2, C3) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component - ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C1, C2, C3, C4), Component.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -2063,18 +1887,18 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3), Component.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, C1, C2, C3, C4), Component.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -2082,18 +1906,18 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4), Component.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -2101,18 +1925,18 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -2120,18 +1944,18 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -2139,18 +1963,18 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -2158,18 +1982,18 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } @@ -2177,15 +2001,14 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> Component - ) where RegexOutput == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf where R0: RegexComponent, R1: RegexComponent { @@ -2194,7 +2017,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0) { @@ -2203,7 +2025,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1) { @@ -2212,7 +2033,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2) { @@ -2221,7 +2041,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3) { @@ -2230,7 +2049,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4) { @@ -2239,7 +2057,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5) { @@ -2248,7 +2065,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6) { @@ -2257,7 +2073,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { @@ -2266,7 +2081,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { @@ -2275,7 +2089,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { @@ -2284,7 +2097,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0) { @@ -2293,7 +2105,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1) { @@ -2302,7 +2113,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2) { @@ -2311,7 +2121,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3) { @@ -2320,7 +2129,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4) { @@ -2329,7 +2137,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5) { @@ -2338,7 +2145,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6) { @@ -2347,7 +2153,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7) { @@ -2356,7 +2161,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { @@ -2365,7 +2169,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { @@ -2374,7 +2177,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1) { @@ -2383,7 +2185,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2) { @@ -2392,7 +2193,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3) { @@ -2401,7 +2201,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4) { @@ -2410,7 +2209,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5) { @@ -2419,7 +2217,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6) { @@ -2428,7 +2225,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7) { @@ -2437,7 +2233,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8) { @@ -2446,7 +2241,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { @@ -2455,7 +2249,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2) { @@ -2464,7 +2257,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3) { @@ -2473,7 +2265,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4) { @@ -2482,7 +2273,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5) { @@ -2491,7 +2281,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6) { @@ -2500,7 +2289,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7) { @@ -2509,7 +2297,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8) { @@ -2518,7 +2305,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8, C9) { @@ -2527,7 +2313,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3) { @@ -2536,7 +2321,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4) { @@ -2545,7 +2329,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5) { @@ -2554,7 +2337,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6) { @@ -2563,7 +2345,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7) { @@ -2572,7 +2353,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8) { @@ -2581,7 +2361,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8, C9) { @@ -2590,7 +2369,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4) { @@ -2599,7 +2377,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5) { @@ -2608,7 +2385,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6) { @@ -2617,7 +2393,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7) { @@ -2626,7 +2401,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8) { @@ -2635,7 +2409,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8, C9) { @@ -2644,7 +2417,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5) { @@ -2653,7 +2425,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6) { @@ -2662,7 +2433,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7) { @@ -2671,7 +2441,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8) { @@ -2680,7 +2449,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8, C9) { @@ -2689,7 +2457,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6) { @@ -2698,7 +2465,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7) { @@ -2707,7 +2473,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8) { @@ -2716,7 +2481,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8, C9) { @@ -2725,7 +2489,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { @@ -2734,7 +2497,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8) { @@ -2743,7 +2505,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8, C9) { @@ -2752,7 +2513,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { @@ -2761,7 +2521,6 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) public static func buildPartialBlock( accumulated: R0, next: R1 ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.RegexOutput == (W1, C9) { @@ -2770,71 +2529,61 @@ extension AlternationBuilder { } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?)> where R: RegexComponent, R.RegexOutput == (W, C0) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C1?)> where R: RegexComponent, R.RegexOutput == (W, C1) { .init(node: .orderedChoice([regex.regex.root])) } } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C1?, C2?)> where R: RegexComponent, R.RegexOutput == (W, C1, C2) { .init(node: .orderedChoice([regex.regex.root])) } } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C1?, C2?, C3?)> where R: RegexComponent, R.RegexOutput == (W, C1, C2, C3) { .init(node: .orderedChoice([regex.regex.root])) } } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C1?, C2?, C3?, C4?)> where R: RegexComponent, R.RegexOutput == (W, C1, C2, C3, C4) { .init(node: .orderedChoice([regex.regex.root])) } } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C1?, C2?, C3?, C4?, C5?)> where R: RegexComponent, R.RegexOutput == (W, C1, C2, C3, C4, C5) { .init(node: .orderedChoice([regex.regex.root])) } } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C1?, C2?, C3?, C4?, C5?, C6?)> where R: RegexComponent, R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { .init(node: .orderedChoice([regex.regex.root])) } } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R: RegexComponent, R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { .init(node: .orderedChoice([regex.regex.root])) } } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R: RegexComponent, R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: .orderedChoice([regex.regex.root])) } } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R: RegexComponent, R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: .orderedChoice([regex.regex.root])) } } @available(SwiftStdlib 5.7, *) extension AlternationBuilder { - @available(SwiftStdlib 5.7, *) - public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R: RegexComponent, R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?)> where R: RegexComponent, R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { .init(node: .orderedChoice([regex.regex.root])) } } @@ -2842,7 +2591,6 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: R @@ -2850,7 +2598,6 @@ extension Capture { self.init(node: .capture(component.regex.root)) } - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: R, as reference: Reference @@ -2858,7 +2605,6 @@ extension Capture { self.init(node: .capture(reference: reference.id, component.regex.root)) } - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: R, @@ -2871,7 +2617,6 @@ extension Capture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: R, @@ -2890,7 +2635,6 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: R, @@ -2903,7 +2647,6 @@ extension TryCapture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( _ component: R, @@ -2924,7 +2667,6 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> R @@ -2932,7 +2674,6 @@ extension Capture { self.init(node: .capture(component().regex.root)) } - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( as reference: Reference, @@ -2943,7 +2684,6 @@ extension Capture { component().regex.root)) } - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> R, @@ -2956,7 +2696,6 @@ extension Capture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( as reference: Reference, @@ -2975,7 +2714,6 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> R, @@ -2988,7 +2726,6 @@ extension TryCapture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( as reference: Reference, @@ -3009,25 +2746,22 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R - ) where RegexOutput == (Substring, W, C0), R.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, W, C1), R.RegexOutput == (W, C1) { self.init(node: .capture(component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C0), R.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, W, C1), R.RegexOutput == (W, C1) { self.init(node: .capture(reference: reference.id, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3035,12 +2769,11 @@ extension Capture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture( reference: reference.id, .transform( @@ -3053,11 +2786,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3065,12 +2797,11 @@ extension TryCapture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture( reference: reference.id, .transform( @@ -3085,28 +2816,25 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0), R.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, W, C1), R.RegexOutput == (W, C1) { self.init(node: .capture(component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0), R.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, W, C1), R.RegexOutput == (W, C1) { self.init(node: .capture( reference: reference.id, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3114,12 +2842,11 @@ extension Capture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture( reference: reference.id, .transform( @@ -3132,11 +2859,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3144,12 +2870,11 @@ extension TryCapture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0), R.RegexOutput == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture( reference: reference.id, .transform( @@ -3164,25 +2889,22 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R - ) where RegexOutput == (Substring, W, C0, C1), R.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, W, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture(component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C0, C1), R.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, W, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture(reference: reference.id, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3190,12 +2912,11 @@ extension Capture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture( reference: reference.id, .transform( @@ -3208,11 +2929,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3220,12 +2940,11 @@ extension TryCapture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture( reference: reference.id, .transform( @@ -3240,28 +2959,25 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1), R.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, W, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture(component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1), R.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, W, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture( reference: reference.id, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3269,12 +2985,11 @@ extension Capture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture( reference: reference.id, .transform( @@ -3287,11 +3002,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3299,12 +3013,11 @@ extension TryCapture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1), R.RegexOutput == (W, C0, C1) { + ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture( reference: reference.id, .transform( @@ -3319,25 +3032,22 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R - ) where RegexOutput == (Substring, W, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, W, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, W, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(reference: reference.id, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3345,12 +3055,11 @@ extension Capture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture( reference: reference.id, .transform( @@ -3363,11 +3072,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3375,12 +3083,11 @@ extension TryCapture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture( reference: reference.id, .transform( @@ -3395,28 +3102,25 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, W, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, W, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture( reference: reference.id, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3424,12 +3128,11 @@ extension Capture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture( reference: reference.id, .transform( @@ -3442,11 +3145,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3454,12 +3156,11 @@ extension TryCapture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2), R.RegexOutput == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture( reference: reference.id, .transform( @@ -3474,25 +3175,22 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture(component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture(reference: reference.id, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3500,12 +3198,11 @@ extension Capture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, .transform( @@ -3518,11 +3215,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3530,12 +3226,11 @@ extension TryCapture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, .transform( @@ -3550,28 +3245,25 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture(component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3579,12 +3271,11 @@ extension Capture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, .transform( @@ -3597,11 +3288,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3609,12 +3299,11 @@ extension TryCapture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3), R.RegexOutput == (W, C0, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, .transform( @@ -3629,25 +3318,22 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture(component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture(reference: reference.id, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3655,12 +3341,11 @@ extension Capture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, .transform( @@ -3673,11 +3358,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3685,12 +3369,11 @@ extension TryCapture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, .transform( @@ -3705,28 +3388,25 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture(component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3734,12 +3414,11 @@ extension Capture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, .transform( @@ -3752,11 +3431,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3764,12 +3442,11 @@ extension TryCapture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4), R.RegexOutput == (W, C0, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, .transform( @@ -3784,25 +3461,22 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(reference: reference.id, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3810,12 +3484,11 @@ extension Capture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, .transform( @@ -3828,11 +3501,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3840,12 +3512,11 @@ extension TryCapture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, .transform( @@ -3860,28 +3531,25 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3889,12 +3557,11 @@ extension Capture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, .transform( @@ -3907,11 +3574,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3919,12 +3585,11 @@ extension TryCapture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, .transform( @@ -3939,25 +3604,22 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(reference: reference.id, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -3965,12 +3627,11 @@ extension Capture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, .transform( @@ -3983,11 +3644,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -3995,12 +3655,11 @@ extension TryCapture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, .transform( @@ -4015,28 +3674,25 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -4044,12 +3700,11 @@ extension Capture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, .transform( @@ -4062,11 +3717,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -4074,12 +3728,11 @@ extension TryCapture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, .transform( @@ -4094,25 +3747,22 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(reference: reference.id, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -4120,12 +3770,11 @@ extension Capture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, .transform( @@ -4138,11 +3787,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -4150,12 +3798,11 @@ extension TryCapture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, .transform( @@ -4170,28 +3817,25 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -4199,12 +3843,11 @@ extension Capture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, .transform( @@ -4217,11 +3860,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -4229,12 +3871,11 @@ extension TryCapture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, .transform( @@ -4249,25 +3890,22 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(reference: reference.id, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -4275,12 +3913,11 @@ extension Capture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, .transform( @@ -4293,11 +3930,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -4305,12 +3941,11 @@ extension TryCapture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, .transform( @@ -4325,28 +3960,25 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -4354,12 +3986,11 @@ extension Capture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, .transform( @@ -4372,11 +4003,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -4384,12 +4014,11 @@ extension TryCapture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, .transform( @@ -4404,25 +4033,22 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture(component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture(reference: reference.id, component.regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -4430,12 +4056,11 @@ extension Capture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture( reference: reference.id, .transform( @@ -4448,11 +4073,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -4460,12 +4084,11 @@ extension TryCapture { component.regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture( reference: reference.id, .transform( @@ -4480,28 +4103,25 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture(component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where RegexOutput == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture( reference: reference.id, component().regex.root)) } - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -4509,12 +4129,11 @@ extension Capture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture( reference: reference.id, .transform( @@ -4527,11 +4146,10 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { - @available(SwiftStdlib 5.7, *) - public init( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any? @@ -4539,12 +4157,11 @@ extension TryCapture { component().regex.root))) } - @available(SwiftStdlib 5.7, *) - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture( reference: reference.id, .transform( diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index f57cd8caa..56e2f3790 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -58,6 +58,17 @@ struct Permutations: Sequence { } } +func captureTypeList( + _ arity: Int, + lowerBound: Int = 0, + optional: Bool = false +) -> String { + let opt = optional ? "?" : "" + return (lowerBound..( accumulated: R0, next: R1 ) -> \(regexTypeName)<\(matchType)> \(whereClause) { @@ -340,24 +348,23 @@ struct VariadicsGenerator: ParsableCommand { } init(kind: QuantifierKind, arity: Int) { - self.disfavored = arity == 0 ? "@_disfavoredOverload\n" : "" + self.disfavored = arity == 0 ? " @_disfavoredOverload\n" : "" self.genericParams = { var result = "" if arity > 0 { - result += "W" - result += (0..( _ component: Component, _ behavior: RegexRepetitionBehavior? = nil @@ -391,8 +397,7 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) extension \(kind.rawValue) { - \(defaultAvailableAttr) - \(params.disfavored)\ + \(params.disfavored)\ public init<\(params.genericParams)>( _ behavior: RegexRepetitionBehavior? = nil, @\(concatBuilderName) _ component: () -> Component @@ -406,7 +411,6 @@ struct VariadicsGenerator: ParsableCommand { """ \(defaultAvailableAttr) extension \(concatBuilderName) { - \(defaultAvailableAttr) public static func buildLimitedAvailability<\(params.genericParams)>( _ component: Component ) -> \(regexTypeName)<\(params.matchType)> \(params.whereClause) { @@ -430,19 +434,18 @@ struct VariadicsGenerator: ParsableCommand { """ } - let disfavored = arity == 0 ? "@_disfavoredOverload\n" : "" + let disfavored = arity == 0 ? " @_disfavoredOverload\n" : "" let genericParams: String = { var result = "" if arity > 0 { - result += "W" - result += (0..( _ component: Component ) \(whereClauseForInit) { @@ -464,7 +467,7 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) extension \(groupName) { \(defaultAvailableAttr) - \(disfavored)\ + \(disfavored)\ public init<\(genericParams)>( @\(concatBuilderName) _ component: () -> Component ) \(whereClauseForInit) { @@ -486,8 +489,7 @@ struct VariadicsGenerator: ParsableCommand { output(""" \(defaultAvailableAttr) extension Repeat { - \(defaultAvailableAttr) - \(params.disfavored)\ + \(params.disfavored)\ public init<\(params.genericParams)>( _ component: Component, count: Int @@ -497,8 +499,7 @@ struct VariadicsGenerator: ParsableCommand { self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - \(defaultAvailableAttr) - \(params.disfavored)\ + \(params.disfavored)\ public init<\(params.genericParams)>( count: Int, @\(concatBuilderName) _ component: () -> Component @@ -508,8 +509,7 @@ struct VariadicsGenerator: ParsableCommand { self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - \(defaultAvailableAttr) - \(params.disfavored)\ + \(params.disfavored)\ public init<\(params.genericParams), R: RangeExpression>( _ component: Component, _ expression: R, @@ -518,8 +518,7 @@ struct VariadicsGenerator: ParsableCommand { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, _ behavior: RegexRepetitionBehavior? = nil, @@ -573,7 +572,6 @@ struct VariadicsGenerator: ParsableCommand { output(""" \(defaultAvailableAttr) extension \(altBuilderName) { - \(defaultAvailableAttr) public static func buildPartialBlock<\(genericParams)>( accumulated: R0, next: R1 ) -> ChoiceOf<\(matchType)> \(whereClause) { @@ -586,7 +584,7 @@ struct VariadicsGenerator: ParsableCommand { func emitUnaryAlternationBuildBlock(arity: Int) { assert(arity > 0) - let captures = (0..(first regex: R) -> ChoiceOf<(W, \(resultCaptures))> \(whereClause) { .init(node: .orderedChoice([regex.regex.root])) } @@ -611,17 +608,17 @@ struct VariadicsGenerator: ParsableCommand { } func emitCapture(arity: Int) { - let disfavored = arity == 0 ? "@_disfavoredOverload\n" : "" + let disfavored = arity == 0 ? " @_disfavoredOverload\n" : "" let genericParams = arity == 0 ? "R: \(regexComponentProtocolName), W" - : "R: \(regexComponentProtocolName), W, " + (0.. String { return arity == 0 ? "(\(baseMatchTypeName), \(newCaptureType))" - : "(\(baseMatchTypeName), \(newCaptureType), " + (0..( _ component: R ) \(whereClauseRaw) { self.init(node: .capture(component.regex.root)) } - \(defaultAvailableAttr) - \(disfavored)\ + \(disfavored)\ public init<\(genericParams)>( _ component: R, as reference: Reference ) \(whereClauseRaw) { self.init(node: .capture(reference: reference.id, component.regex.root)) } - \(defaultAvailableAttr) - \(disfavored)\ + \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -661,8 +655,7 @@ struct VariadicsGenerator: ParsableCommand { component.regex.root))) } - \(defaultAvailableAttr) - \(disfavored)\ + \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, as reference: Reference, @@ -680,8 +673,7 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) extension TryCapture { - \(defaultAvailableAttr) - \(disfavored)\ + \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, transform: @escaping (Substring) throws -> NewCapture? @@ -693,8 +685,7 @@ struct VariadicsGenerator: ParsableCommand { component.regex.root))) } - \(defaultAvailableAttr) - \(disfavored)\ + \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, as reference: Reference, @@ -714,16 +705,14 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) extension Capture { - \(defaultAvailableAttr) - \(disfavored)\ + \(disfavored)\ public init<\(genericParams)>( @\(concatBuilderName) _ component: () -> R ) \(whereClauseRaw) { self.init(node: .capture(component().regex.root)) } - \(defaultAvailableAttr) - \(disfavored)\ + \(disfavored)\ public init<\(genericParams)>( as reference: Reference, @\(concatBuilderName) _ component: () -> R @@ -733,8 +722,7 @@ struct VariadicsGenerator: ParsableCommand { component().regex.root)) } - \(defaultAvailableAttr) - \(disfavored)\ + \(disfavored)\ public init<\(genericParams), NewCapture>( @\(concatBuilderName) _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -746,8 +734,7 @@ struct VariadicsGenerator: ParsableCommand { component().regex.root))) } - \(defaultAvailableAttr) - \(disfavored)\ + \(disfavored)\ public init<\(genericParams), NewCapture>( as reference: Reference, @\(concatBuilderName) _ component: () -> R, @@ -765,8 +752,7 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) extension TryCapture { - \(defaultAvailableAttr) - \(disfavored)\ + \(disfavored)\ public init<\(genericParams), NewCapture>( @\(concatBuilderName) _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture? @@ -778,8 +764,7 @@ struct VariadicsGenerator: ParsableCommand { component().regex.root))) } - \(defaultAvailableAttr) - \(disfavored)\ + \(disfavored)\ public init<\(genericParams), NewCapture>( as reference: Reference, @\(concatBuilderName) _ component: () -> R, diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index dab53cc1c..345e80e22 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -1549,5 +1549,6 @@ extension RegexTests { // TODO: Add test for implied grapheme cluster requirement at group boundaries // TODO: Add test for grapheme boundaries at start/end of match + } From 96df14d0379acbe0fce937f39d7da690a3186faa Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Tue, 26 Apr 2022 13:28:17 -0700 Subject: [PATCH 121/133] Fix cut-off sentence. Co-authored-by: Nate Cook --- Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift b/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift index c06643aee..bf379fc14 100644 --- a/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift +++ b/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift @@ -57,7 +57,7 @@ extension PrettyPrinter { /// Outputs a string directly, without termination or /// indentation, and without updating any internal state. /// - /// This is the low-level interface to the pret + /// This is the low-level interface to the pretty printer. /// /// - Note: If `s` includes a newline, even at the end, /// this method does not update any tracking state. From 12ef33b7ee7b8445b678a95c3b95ae54201524e5 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 26 Apr 2022 14:58:40 -0700 Subject: [PATCH 122/133] Update PatternConverter --- .../Regex/Printing/PrettyPrinter.swift | 3 + .../_StringProcessing/PrintAsPattern.swift | 846 +++++++++++++++--- 2 files changed, 709 insertions(+), 140 deletions(-) diff --git a/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift b/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift index f1d8c83b0..30fa3e6dc 100644 --- a/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift +++ b/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift @@ -32,6 +32,9 @@ public struct PrettyPrinter { // The indentation level fileprivate var indentLevel = 0 + + // The current default quantification behavior + public var quantificationBehavior: AST.Quantification.Kind = .eager } // MARK: - Raw interface diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index 91626eb5c..3ab00f15f 100644 --- a/Sources/_StringProcessing/PrintAsPattern.swift +++ b/Sources/_StringProcessing/PrintAsPattern.swift @@ -57,7 +57,17 @@ extension PrettyPrinter { mutating func printAsPattern(_ ast: AST) { // TODO: Handle global options... let node = ast.root.dslTreeNode - printAsPattern(convertedFromAST: node) + + // If we have any named captures, create referencs to those above the regex. + let namedCaptures = node.getNamedCaptures() + + for namedCapture in namedCaptures { + print("let \(namedCapture) = Reference(Substring.self)") + } + + printBlock("Regex") { printer in + printer.printAsPattern(convertedFromAST: node) + } } // FIXME: Use of back-offs like height and depth @@ -76,29 +86,32 @@ extension PrettyPrinter { switch node { case let .orderedChoice(a): - printBlock("Alternation") { printer in + printBlock("ChoiceOf") { printer in a.forEach { printer.printAsPattern(convertedFromAST: $0) } } case let .concatenation(c): - printBlock("Concatenation") { printer in - c.forEach { - printer.printAsPattern(convertedFromAST: $0) - } + c.forEach { + printAsPattern(convertedFromAST: $0) } case let .nonCapturingGroup(kind, child): - let kind = kind.ast._patternBase - printBlock("Group(\(kind))") { printer in - printer.printAsPattern(convertedFromAST: child) + switch kind.ast { + case .atomicNonCapturing: + printBlock("Local") { printer in + printer.printAsPattern(convertedFromAST: child) + } + + default: + printAsPattern(convertedFromAST: child) } case let .capture(name, _, child): - var cap = "capture" + var cap = "Capture" if let n = name { - cap += "(\(n))" + cap += "(as: \(n))" } printBlock(cap) { printer in printer.printAsPattern(convertedFromAST: child) @@ -109,41 +122,38 @@ extension PrettyPrinter { case let .quantification(amount, kind, child): let amount = amount.ast._patternBase - let kind = (kind.ast ?? .eager)._patternBase - printBlock("\(amount)(\(kind))") { printer in + var kind = kind.ast?._patternBase ?? "" + + // If we've updated our quantification behavior, then use that. This + // occurs in scenarios where we use things like '(?U)' to indicate that + // we want reluctant default quantification behavior. + if quantificationBehavior != .eager { + kind = quantificationBehavior._patternBase + } + + var blockName = "\(amount)(\(kind))" + + if kind == ".eager" { + blockName = "\(amount)" + } + + printBlock(blockName) { printer in printer.printAsPattern(convertedFromAST: child) } case let .atom(a): - switch a { - case .any: - print(".any") - - case let .char(c): - print(String(c)._quoted) - - case let .scalar(s): - let hex = String(s.value, radix: 16, uppercase: true) - print("\\u{\(hex)}"._quoted) - - case let .unconverted(a): - // TODO: is this always right? - // TODO: Convert built-in character classes - print(a.ast._patternBase) - - case .assertion: - print("/* TODO: assertions */") - case .backreference: - print("/* TOOD: backreferences */") - case .symbolicReference: - print("/* TOOD: symbolic references */") - case .changeMatchingOptions: - print("/* TODO: change matching options */") + if case .unconverted(let a) = a, a.ast.isUnprintableAtom { + print("#/\(a.ast._regexBase)/#") + return + } + + if let pattern = a._patternBase(&self) { + print(pattern) } case .trivia: - // What should we do? Maybe keep comments, etc? - print("") + // We never print trivia + break case .empty: print("") @@ -180,11 +190,118 @@ extension PrettyPrinter { // TODO: Some way to integrate this with conversion... mutating func printAsPattern( - _ ccc: DSLTree.CustomCharacterClass + _ ccc: DSLTree.CustomCharacterClass, + terminateLine: Bool = true ) { - let inv = ccc.isInverted ? "inverted: true" : "" - printBlock("CharacterClass(\(inv))") { printer in - ccc.members.forEach { printer.printAsPattern($0) } + if ccc.hasUnprintableProperty { + printAsRegex(ccc, terminateLine: terminateLine) + return + } + + defer { + if ccc.isInverted { + printIndented { printer in + printer.indent() + + if terminateLine { + printer.print(".inverted") + } else { + printer.output(".inverted") + } + } + } + } + + // If we only have 1 member, then we can emit it without the extra + // CharacterClass initialization + if ccc.members.count == 1 { + printAsPattern(ccc.members[0]) + + if terminateLine { + self.terminateLine() + } + + return + } + + var charMembers = "" + + let nonCharMembers = ccc.members.filter { + switch $0 { + case let .atom(a): + switch a { + case let .char(c): + charMembers.append(c) + + if c == "\\" { + charMembers.append(c) + } + + return false + case let .scalar(s): + charMembers += "\\u{\(String(s.value, radix: 16, uppercase: true))}" + return false + case .unconverted(_): + return true + default: + return true + } + + case let .quotedLiteral(s): + charMembers += s + return false + + case .trivia(_): + return false + + default: + return true + } + } + + // Also in the same vein, if we have a few atom members but no + // nonAtomMembers, then we can emit a single .anyOf(...) for them. + if !charMembers.isEmpty, nonCharMembers.isEmpty { + if terminateLine { + print(".anyOf(\(charMembers._quoted))") + } else { + indent() + output(".anyOf(\(charMembers._quoted))") + } + return + } + + // Otherwise, use the CharacterClass initialization with multiple members. + print("CharacterClass(") + printIndented { printer in + printer.indent() + + if !charMembers.isEmpty { + printer.output(".anyOf(\(charMembers._quoted))") + + if nonCharMembers.count > 0 { + printer.output(",") + } + + printer.terminateLine() + } + + for (i, member) in nonCharMembers.enumerated() { + printer.printAsPattern(member) + + if i != nonCharMembers.count - 1 { + printer.output(",") + } + + printer.terminateLine() + } + } + + if terminateLine { + print(")") + } else { + indent() + output(")") } } @@ -194,73 +311,324 @@ extension PrettyPrinter { ) { switch member { case let .custom(ccc): - printAsPattern(ccc) + printAsPattern(ccc, terminateLine: false) + case let .range(lhs, rhs): - if case let .char(lhs) = lhs, - case let .char(rhs) = rhs { + if let lhs = lhs._patternBase(&self), let rhs = rhs._patternBase(&self) { indent() - output(String(lhs)._quoted) + output("(") + output(lhs) output("...") - output(String(rhs)._quoted) - terminateLine() - } else { - print("// TODO: Range \(lhs) to \(rhs)") + output(rhs) + output(")") } + case let .atom(a): - if case let .char(c) = a { - print(String(c)._quoted) + indent() + switch a { + case let .char(c): + output(".anyOf(\(String(c)._quoted))") + case let .scalar(s): + output(".anyOf(\"\\u{\(String(s.value, radix: 16))}\")") + case let .unconverted(a): + output(a.ast._patternBase) + default: + print(" // TODO: Atom \(a)") + } + + case .quotedLiteral(let s): + output(".anyOf(\(s._quoted))") + + case .trivia(_): + // We never print trivia + break + + case .intersection(let first, let second): + printAsPattern(first) + printIndented { printer in + printer.indent() + printer.output(".intersection(") + printer.printAsPattern(second, terminateLine: false) + printer.output(")") + } + + case .subtraction(let first, let second): + printAsPattern(first) + printIndented { printer in + printer.indent() + printer.output(".subtracting(") + printer.printAsPattern(second, terminateLine: false) + printer.output(")") + } + + case .symmetricDifference(let first, let second): + printAsPattern(first) + printIndented { printer in + printer.indent() + printer.output(".symmetricDifference(") + printer.printAsPattern(second, terminateLine: false) + printer.output(")") + } + } + } + + mutating func printAsRegex( + _ ccc: DSLTree.CustomCharacterClass, + asFullRegex: Bool = true, + terminateLine: Bool = true + ) { + indent() + + if asFullRegex { + output("#/") + } + + output("[") + + if ccc.isInverted { + output("^") + } + + for member in ccc.members { + printAsRegex(member) + } + + output("]") + + if asFullRegex { + if terminateLine { + print("/#") } else { - print(" // TODO: Atom \(a) ") + output("/#") } + } + } + + mutating func printAsRegex(_ member: DSLTree.CustomCharacterClass.Member) { + switch member { + case let .custom(ccc): + printAsRegex(ccc, terminateLine: false) + + case let .range(lhs, rhs): + output(lhs._regexBase) + output("-") + output(rhs._regexBase) + + case let .atom(a): + switch a { + case let .char(c): + output(String(c)) + case let .unconverted(a): + output(a.ast._regexBase) + default: + print(" // TODO: Atom \(a)") + } + case .quotedLiteral(let s): - print("// TODO: quote \(s._quoted) in custom character classes (should we split it?)") - case .trivia(let t): - // TODO: We might want to output comments... - _ = t - case .symmetricDifference, .intersection, .subtraction: - print("// TODO: Set operation: \(member)") + output("\\Q\(s)\\E") + + case .trivia(_): + // We never print trivia + break + + case .intersection(let first, let second): + printAsRegex(first, asFullRegex: false, terminateLine: false) + output("&&") + printAsRegex(second, asFullRegex: false, terminateLine: false) + + case .subtraction(let first, let second): + printAsRegex(first, asFullRegex: false, terminateLine: false) + output("--") + printAsRegex(second, asFullRegex: false, terminateLine: false) + + case .symmetricDifference(let first, let second): + printAsRegex(first, asFullRegex: false, terminateLine: false) + output("~~") + printAsRegex(second, asFullRegex: false, terminateLine: false) } } } extension String { // TODO: Escaping? - fileprivate var _quoted: String { "\"\(self)\"" } + fileprivate var _quoted: String { + "\"\(self.replacing("\"", with: "\\\""))\"" + } } extension AST.Atom.AssertionKind { // TODO: Some way to integrate this with conversion... var _patternBase: String { switch self { - case .startOfSubject: return "Anchor(.startOfSubject)" - case .endOfSubject: return "Anchor(.endOfSubject)" - case .textSegment: return "Anchor(.textSegment)" - case .notTextSegment: return "Anchor(.notTextSegment)" - case .startOfLine: return "Anchor(.startOfLine)" - case .endOfLine: return "Anchor(.endOfLine)" - case .wordBoundary: return "Anchor(.wordBoundary)" - case .notWordBoundary: return "Anchor(.notWordBoundary)" - - case .resetStartOfMatch: - return "Anchor(.resetStartOfMatch)" + case .startOfLine: + return "Anchor.startOfLine" + case .endOfLine: + return "Anchor.endOfLine" + case .wordBoundary: + return "Anchor.wordBoundary" + case .notWordBoundary: + return "Anchor.wordBoundary.inverted" + case .startOfSubject: + return "Anchor.startOfSubject" + case .endOfSubject: + return "Anchor.endOfSubject" case .endOfSubjectBeforeNewline: - return "Anchor(.endOfSubjectBeforeNewline)" + return "Anchor.endOfSubjectBeforeNewline" + case .textSegment: + return "Anchor.textSegmentBoundary" + case .notTextSegment: + return "Anchor.textSegmentBoundary.inverted" case .firstMatchingPositionInSubject: - return "Anchor(.firstMatchingPositionInSubject)" + return "Anchor.firstMatchingPositionInSubject" + + case .resetStartOfMatch: + return "TODO: Assertion resetStartOfMatch" } } } extension AST.Atom.CharacterProperty { - // TODO: Some way to integrate this with conversion... - var _patternBase: String { - "Property(\(kind._patternBase)\(isInverted ? ", inverted: true" : ""))" + var isUnprintableProperty: Bool { + switch kind { + case .ascii: + return true + case .binary(let b, value: _): + return isUnprintableBinary(b) + case .generalCategory(let gc): + return isUnprintableGeneralCategory(gc) + case .posix(let p): + return isUnprintablePOSIX(p) + case .script(_), .scriptExtension(_): + return true + default: + return false + } + } + + func isUnprintableBinary(_ binary: Unicode.BinaryProperty) -> Bool { + // List out the ones we can print because that list is smaller. + switch binary { + case .whitespace: + return false + default: + return true + } + } + + func isUnprintableGeneralCategory( + _ gc: Unicode.ExtendedGeneralCategory + ) -> Bool { + // List out the ones we can print because that list is smaller. + switch gc { + case .decimalNumber: + return false + default: + return true + } + } + + func isUnprintablePOSIX(_ posix: Unicode.POSIXProperty) -> Bool { + // List out the ones we can print because that list is smaller. + switch posix { + case .xdigit: + return false + case .word: + return false + default: + return true + } } } -extension AST.Atom.CharacterProperty.Kind { + +extension AST.Atom.CharacterProperty { // TODO: Some way to integrate this with conversion... var _patternBase: String { - "/* TODO: character properties */" + if isUnprintableProperty { + return _regexBase + } + + return _dslBase + } + + var _dslBase: String { + switch kind { + case .binary(let bp, _): + switch bp { + case .whitespace: + return ".whitespace" + default: + return "" + } + + case .generalCategory(let gc): + switch gc { + case .decimalNumber: + return ".digit" + default: + return "" + } + + case .posix(let p): + switch p { + case .xdigit: + return ".hexDigit" + case .word: + return ".word" + default: + return "" + } + + default: + return "" + } + } + + var _regexBase: String { + switch kind { + case .ascii: + return "[:\(isInverted ? "^" : "")ascii:]" + + case .binary(let b, value: _): + if isInverted { + return "[^\\p{\(b.rawValue)}]" + } else { + return "\\p{\(b.rawValue)}" + } + + case .generalCategory(let gc): + if isInverted { + return "[^\\p{\(gc.rawValue)}]" + } else { + return "\\p{\(gc.rawValue)}" + } + + case .posix(let p): + return "[:\(isInverted ? "^" : "")\(p.rawValue):]" + + case .script(let s): + return "[:\(isInverted ? "^" : "")script=\(s.rawValue):]" + + case .scriptExtension(let s): + return "[:\(isInverted ? "^" : "")scx=\(s.rawValue):]" + + default: + return " // TODO: Property \(self)" + } + } +} + +extension AST.Atom { + var isUnprintableAtom: Bool { + switch kind { + case .keyboardControl, .keyboardMeta, .keyboardMetaControl: + return true + case .namedCharacter(_): + return true + case .property(let p): + return p.isUnprintableProperty + default: + return false + } } } @@ -278,6 +646,14 @@ extension AST.Atom { return anchor._patternBase } + if isUnprintableAtom { + return _regexBase + } + + return _dslBase + } + + var _dslBase: String { switch kind { case let .char(c): return String(c) @@ -287,21 +663,62 @@ extension AST.Atom { return "\\u{\(hex)}" case let .property(p): - return p._patternBase - + return p._dslBase + case let .escaped(e): - // TODO: API names instead of case names - return ".\(e)" - - case .keyboardControl: - return " /* TODO: keyboard control */" - - case .keyboardMeta: - return " /* TODO: keyboard meta */" - - case .keyboardMetaControl: - return " /* TODO: keyboard meta-control */" - + switch e { + // Anchors + case .wordBoundary: + return "Anchor.wordBoundary" + case .notWordBoundary: + return "Anchor.wordBoundary.inverted" + case .startOfSubject: + return "Anchor.startOfSubject" + case .endOfSubject: + return "Anchor.endOfSubject" + case .endOfSubjectBeforeNewline: + return "Anchor.endOfSubjectBeforeNewline" + case .firstMatchingPositionInSubject: + return "Anchor.firstMatchingPositionInSubject" + case .textSegment: + return "Anchor.textSegmentBoundary" + case .notTextSegment: + return "Anchor.textSegmentBoundary.inverted" + + // Character Classes + case .decimalDigit: + return ".digit" + case .notDecimalDigit: + return ".digit.inverted" + case .horizontalWhitespace: + return ".horizontalWhitespace" + case .notHorizontalWhitespace: + return ".horizontalWhitespace.inverted" + case .whitespace: + return ".whitespace" + case .notWhitespace: + return ".whitespace.inverted" + case .wordCharacter: + return ".word" + case .notWordCharacter: + return ".word.inverted" + case .graphemeCluster: + return ".anyGraphemeCluster" + case .newlineSequence: + return ".newlineSequence" + case .notNewline: + return ".newlineSequence.inverted" + case .verticalTab: + return ".verticalWhitespace" + case .notVerticalTab: + return ".verticalWhitespace.inverted" + + // Literal single characters all get converted into DSLTree.Atom.scalar + + default: + return "TODO: escaped \(e)" + } + case .namedCharacter: return " /* TODO: named character */" @@ -325,51 +742,61 @@ extension AST.Atom { case .changeMatchingOptions: return "/* TODO: change matching options */" + + // Every other case we've already decided cannot be represented inside the + // DSL. + default: + return "" } } -} - -extension AST.Group.Kind { - var _patternBase: String { - switch self { - case .capture: - // TODO: We probably want this to be a property after group - return ".capture" - - case .namedCapture(let n): - return "name: \"\(n)\"" - - case .balancedCapture: - return "/* TODO: balanced captures */" - - case .nonCapture: return "" - - case .nonCaptureReset: - return "/* TODO: non-capture reset */" - - case .atomicNonCapturing: - return "/* TODO: atomicNonCapturing */" - case .lookahead: - return "/* TODO: lookahead */" - case .negativeLookahead: - return "/* TODO: negativeLookahead */" - case .nonAtomicLookahead: - return "/* TODO: nonAtomicLookahead */" - case .lookbehind: - return "/* TODO: lookbehind */" - case .negativeLookbehind: - return "/* TODO: negativeLookbehind */" - case .nonAtomicLookbehind: - return "/* TODO: nonAtomicLookbehind */" - case .scriptRun: - return "/* TODO: scriptRun */" - case .atomicScriptRun: - return "/* TODO: atomicScriptRun */" + + var _regexBase: String { + switch kind { + case let .char(c): + return String(c) + + case let .scalar(s): + let hex = String(s.value, radix: 16, uppercase: true) + return "\\u{\(hex)}" + + case let .property(p): + return p._regexBase + + case let .escaped(e): + return "\\\(e.character)" + + case .keyboardControl(let k): + return "\\c\(k)" + + case .keyboardMeta(let k): + return "\\M-\(k)" + + case .keyboardMetaControl(let k): + return "\\M-\\C-\(k)" + + case .namedCharacter(let n): + return "\\N{\(n)}" + + case .any: + return "." + + case .startOfLine, .endOfLine: + fatalError("unreachable") + + case .backreference: + return " /* TODO: back reference */" + + case .subpattern: + return " /* TODO: subpattern */" + + case .callout: + return " /* TODO: callout */" + + case .backtrackingDirective: + return " /* TODO: backtracking directive */" + case .changeMatchingOptions: - return "/* TODO: changeMatchingOptions */" - - @unknown default: - fatalError() + return "/* TODO: change matching options */" } } } @@ -379,11 +806,11 @@ extension AST.Quantification.Amount { switch self { case .zeroOrMore: return "ZeroOrMore" case .oneOrMore: return "OneOrMore" - case .zeroOrOne: return "ZeroOrOne" - case let .exactly(n): return "Quantitified(exactly: \(n))" - case let .nOrMore(n): return "Quantified(\(n)...)" - case let .upToN(n): return "Quantified(...\(n))" - case let .range(n, m): return "Quantified(\(n)...\(m))" + case .zeroOrOne: return "Optionally" + case let .exactly(n): return "Repeat(count: \(n.value))" + case let .nOrMore(n): return "Repeat(\(n.value)...)" + case let .upToN(n): return "Repeat(...\(n.value))" + case let .range(n, m): return "Repeat(\(n.value)...\(m.value))" } } } @@ -403,3 +830,142 @@ extension DSLTree.QuantificationKind { (ast ?? .eager)._patternBase } } + +extension DSLTree.CustomCharacterClass.Member { + var isUnprintableMember: Bool { + switch self { + case .atom(.unconverted(let a)): + return a.ast.isUnprintableAtom + case .custom(let c): + return c.hasUnprintableProperty + case .range(.unconverted(let lhs), .unconverted(let rhs)): + return lhs.ast.isUnprintableAtom || rhs.ast.isQuantifiable + case .intersection(let first, let second): + return first.hasUnprintableProperty || second.hasUnprintableProperty + case .subtraction(let first, let second): + return first.hasUnprintableProperty || second.hasUnprintableProperty + case .symmetricDifference(let first, let second): + return first.hasUnprintableProperty || second.hasUnprintableProperty + default: + return false + } + } +} + +extension DSLTree.CustomCharacterClass { + var hasUnprintableProperty: Bool { + members.contains { + $0.isUnprintableMember + } + } +} + +extension DSLTree.Atom { + func _patternBase(_ printer: inout PrettyPrinter) -> String? { + switch self { + case .any: + return ".any" + + case let .char(c): + return String(c)._quoted + + case let .scalar(s): + let hex = String(s.value, radix: 16, uppercase: true) + return "\\u{\(hex)}"._quoted + + case let .unconverted(a): + if a.ast.isUnprintableAtom { + return "#/\(a.ast._regexBase)/#" + } else { + return a.ast._dslBase + } + + case .assertion(let a): + return a.ast._patternBase + + case .backreference(_): + return "/* TOOD: backreferences */" + + case .symbolicReference: + return "/* TOOD: symbolic references */" + + case .changeMatchingOptions(let matchingOptions): + for add in matchingOptions.ast.adding { + switch add.kind { + case .reluctantByDefault: + printer.quantificationBehavior = .reluctant + default: + break + } + } + } + + return nil + } + + var _regexBase: String { + switch self { + case .any: + return "." + + case let .char(c): + return String(c) + + case let .scalar(s): + let hex = String(s.value, radix: 16, uppercase: true) + return "\\u{\(hex)}"._quoted + + case let .unconverted(a): + return a.ast._regexBase + + case .assertion: + return "/* TODO: assertions */" + case .backreference: + return "/* TOOD: backreferences */" + case .symbolicReference: + return "/* TOOD: symbolic references */" + case .changeMatchingOptions(let matchingOptions): + var result = "" + + for add in matchingOptions.ast.adding { + switch add.kind { + case .reluctantByDefault: + result += "(?U)" + default: + break + } + } + + return result + } + } +} + +extension DSLTree.Node { + func getNamedCaptures() -> [String] { + var result: [String] = [] + + switch self { + case .capture(let name, _, _): + if let name = name { + result.append(name) + } + + case .concatenation(let nodes): + for node in nodes { + result += node.getNamedCaptures() + } + + case .convertedRegexLiteral(let node, _): + result += node.getNamedCaptures() + + case .quantification(_, _, let node): + result += node.getNamedCaptures() + + default: + break + } + + return result + } +} From 0e59bdf59b4b4d96381aeb6add164fdae31584ca Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Tue, 26 Apr 2022 20:45:30 -0600 Subject: [PATCH 123/133] Update Sources/_StringProcessing/Regex/Match.swift --- Sources/_StringProcessing/Regex/Match.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index dd36c8823..9937f1e03 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -191,7 +191,6 @@ extension String { extension RegexComponent { public static func ~=(regex: Self, input: String) -> Bool { input.wholeMatch(of: regex) != nil - try? r.regex.wholeMatch(in: self) } public static func ~=(regex: Self, input: Substring) -> Bool { From ac618f63eb2071703406c806f44ec63f57247f78 Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Wed, 27 Apr 2022 11:08:27 -0700 Subject: [PATCH 124/133] Back out an accidental source change. Confirmed (using the command below) that this branch now contains only changes to doc comments, changes to // comments where content was moved into or out of a doc comment, and one spelling correction to code. % git diff origin/main... | grep -v '^+ *///\|- *///' | grep -v '^@@' | grep -v '^ ' | grep -v '^+++\|^---' | grep -v '^diff --git' | grep -v '^index ' + // Individual public API functions are in the generated Variadics.swift file. +// For now, we use String as the source while prototyping... + + // NOTE: Currently, this means we have raw quotes. + // Better would be to have real Swift string delimiter parsing logic. + + // NOTE: traditional comments are not nested. Currently, we are neither. + // Traditional comments can't have `)`, not even escaped in them either, we + // can. Traditional comments can have `*/` in them, we can't without + // escaping. We don't currently do escaping. + - // Finish, flush, and clear. Returns the rendered output + // Finish, flush, and clear. + // + // - Returns: The rendered output. + // Note: The `Script` enum includes the "meta" script type "Katakana_Or_Hiragana", which + // isn't defined by https://www.unicode.org/Public/UCD/latest/ucd/Scripts.txt, + // but is defined by https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt. + // We may want to split it out, as it's the only case that is a union of + // other script types. + +// TODO: These should become aliases for the Block (blk) Unicode character +// property. + - // Ensures `.0` always refers to the whole match. - // Allows `.0` when `Match` is not a tuple. - func withInversion(_ invertion: Bool) -> Self { + func withInversion(_ inversion: Bool) -> Self { - if invertion { + if inversion { --- Sources/_StringProcessing/Regex/Match.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 9937f1e03..8172e993b 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -165,7 +165,7 @@ extension Regex { } @available(SwiftStdlib 5.7, *) -extension String { +extension BidirectionalCollection where SubSequence == Substring { /// Checks for a match against the string in its entirety. /// /// - Parameter r: The regular expression being matched. From 7d03a1e6154d45d834037943138fdb2c90b2ff34 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 27 Apr 2022 20:12:48 +0100 Subject: [PATCH 125/133] Introduce new compiler interface Add the SPI interface `swiftCompilerLexRegexLiteral` and `swiftCompilerParseRegexLiteral` for the Swift compiler to call into. This allows us to avoid depending on other library API on the compiler side, while letting it keep the bridging gunk. While we're here, add an extra `String` return for the parsing function that could allow us to change the regex emission format in the future. This still needs to be plumbed through on the complier side though. --- .../Regex/Parse/CompilerInterface.swift | 115 ++++++++++++++++ .../_RegexParser/Regex/Parse/Mocking.swift | 128 ------------------ Tests/RegexTests/ParseTests.swift | 34 ++--- 3 files changed, 130 insertions(+), 147 deletions(-) create mode 100644 Sources/_RegexParser/Regex/Parse/CompilerInterface.swift delete mode 100644 Sources/_RegexParser/Regex/Parse/Mocking.swift diff --git a/Sources/_RegexParser/Regex/Parse/CompilerInterface.swift b/Sources/_RegexParser/Regex/Parse/CompilerInterface.swift new file mode 100644 index 000000000..0856361d8 --- /dev/null +++ b/Sources/_RegexParser/Regex/Parse/CompilerInterface.swift @@ -0,0 +1,115 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +// The version number for the regex. This gets emitted as an argument to the +// Regex(_regexString:version:) initializer and should be bumped if the format +// of the regex string needs to be changed in such a that requires the runtime +// to updated. +public let currentRegexLiteralFormatVersion = 1 + +@_spi(CompilerInterface) +public struct CompilerLexError: Error { + public var message: String + public var location: UnsafeRawPointer + public var completelyErroneous: Bool +} + +/// Interface for the Swift compiler. +/// +/// Attempt to lex a regex literal string. +/// +/// - Parameters: +/// - start: The pointer at which to start lexing the literal. +/// - bufferEnd: A pointer to the end of the buffer, which should not be lexed +/// past. +/// - mustBeRegex: Whether we expect a regex literal to be lexed here. If +/// `false`, a regex literal will only be lexed if it does not +/// produce an error. +/// +/// - Returns: If a regex literal was lexed, `resumePtr` specifies where to +/// resume lexing and `error` specifies a lexing error to emit. If +/// a regex literal was not lexed, `nil` is returned. +/// +@_spi(CompilerInterface) +public func swiftCompilerLexRegexLiteral( + start: UnsafeRawPointer, bufferEnd: UnsafeRawPointer, mustBeRegex: Bool +) -> (resumePtr: UnsafeRawPointer, error: CompilerLexError?)? { + do { + let (_, _, endPtr) = try lexRegex(start: start, end: bufferEnd) + return (resumePtr: endPtr, error: nil) + } catch let error as DelimiterLexError { + if !mustBeRegex { + // This token can be something else. Let the client fallback. + return nil + } + let completelyErroneous: Bool + switch error.kind { + case .unterminated, .multilineClosingNotOnNewline: + // These can be recovered from. + completelyErroneous = false + case .unprintableASCII, .invalidUTF8: + // We don't currently have good recovery behavior for these. + completelyErroneous = true + case .unknownDelimiter: + // An unknown delimiter should be recovered from, as we may want to try + // lex something else. + return nil + } + // For now every lexer error is emitted at the starting delimiter. + let compilerError = CompilerLexError( + message: "\(error)", location: start, + completelyErroneous: completelyErroneous + ) + return (error.resumePtr, compilerError) + } catch { + fatalError("Should be a DelimiterLexError") + } +} + +@_spi(CompilerInterface) +public struct CompilerParseError: Error { + public var message: String + public var location: String.Index? +} + +/// Interface for the Swift compiler. +/// +/// Attempt to parse a regex literal string. +/// +/// - Parameters: +/// - input: The regex input string, including delimiters. +/// - captureBufferOut: A buffer into which the captures of the regex will +/// be encoded into upon a successful parse. +/// +/// - Returns: The string to emit along with its version number. +/// - Throws: `CompilerParseError` if there was a parsing error. +@_spi(CompilerInterface) +public func swiftCompilerParseRegexLiteral( + _ input: String, captureBufferOut: UnsafeMutableRawBufferPointer +) throws -> (regexToEmit: String, version: Int) { + do { + let ast = try parseWithDelimiters(input) + // Serialize the capture structure for later type inference. + assert(captureBufferOut.count >= input.utf8.count) + ast.captureStructure.encode(to: captureBufferOut) + + // For now we just return the input as the regex to emit. This could be + // changed in the future if need to back-deploy syntax to something already + // known to the matching engine, or otherwise change the format. Note + // however that it will need plumbing through on the compiler side. + return (regexToEmit: input, version: currentRegexLiteralFormatVersion) + } catch { + throw CompilerParseError( + message: "cannot parse regular expression: \(String(describing: error))", + location: (error as? LocatedErrorProtocol)?.location.start + ) + } +} diff --git a/Sources/_RegexParser/Regex/Parse/Mocking.swift b/Sources/_RegexParser/Regex/Parse/Mocking.swift deleted file mode 100644 index 56294e2d3..000000000 --- a/Sources/_RegexParser/Regex/Parse/Mocking.swift +++ /dev/null @@ -1,128 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// -//===----------------------------------------------------------------------===// - -@available(*, deprecated, message: "moving to SwiftCompilerModules") -private func copyCString(_ str: String) -> UnsafePointer { - let count = str.utf8.count + 1 - return str.withCString { - assert($0[count-1] == 0) - let ptr = UnsafeMutablePointer.allocate(capacity: count) - ptr.initialize(from: $0, count: count) - return UnsafePointer(ptr) - } -} - -/// Interface for libswift. -/// -/// Attempt to lex a regex literal string. -/// -/// - Parameters: -/// - CurPtrPtr: A pointer to the current pointer of lexer, which should be -/// the start of the literal. This will be advanced to the point -/// at which the lexer should resume, or will remain the same if -/// this is not a regex literal. -/// - BufferEnd: A pointer to the end of the buffer, which should not be lexed -/// past. -/// - ErrorOut: If an error is encountered, this will be set to the error -/// string. -/// -/// - Returns: A bool indicating whether lexing was completely erroneous, and -/// cannot be recovered from, or false if there either was no error, -/// or there was a recoverable error. -@available(*, deprecated, message: "moving to SwiftCompilerModules") -func libswiftLexRegexLiteral( - _ curPtrPtr: UnsafeMutablePointer?>?, - _ bufferEndPtr: UnsafePointer?, - _ errOut: UnsafeMutablePointer?>? -) -> /*CompletelyErroneous*/ CBool { - guard let curPtrPtr = curPtrPtr, let inputPtr = curPtrPtr.pointee, - let bufferEndPtr = bufferEndPtr - else { - fatalError("Expected lexing pointers") - } - guard let errOut = errOut else { fatalError("Expected error out param") } - - do { - let (_, _, endPtr) = try lexRegex(start: inputPtr, end: bufferEndPtr) - curPtrPtr.pointee = endPtr.assumingMemoryBound(to: CChar.self) - return false - } catch let error as DelimiterLexError { - if error.kind == .unknownDelimiter { - // An unknown delimiter should be recovered from, as we may want to try - // lex something else. - return false - } - errOut.pointee = copyCString("\(error)") - curPtrPtr.pointee = error.resumePtr.assumingMemoryBound(to: CChar.self) - - switch error.kind { - case .unterminated, .multilineClosingNotOnNewline: - // These can be recovered from. - return false - case .unprintableASCII, .invalidUTF8: - // We don't currently have good recovery behavior for these. - return true - case .unknownDelimiter: - fatalError("Already handled") - } - } catch { - fatalError("Should be a DelimiterLexError") - } -} - -// The version number for the regex. This gets emitted as an argument to the -// Regex(_regexString:version:) initializer and should be bumped if the format -// of the regex string needs to be changed in such a that requires the runtime -// to updated. -public let currentRegexLiteralFormatVersion: CUnsignedInt = 1 - -/// Interface for libswift. -/// -/// - Parameters: -/// - inputPtr: A null-terminated C string. -/// - errOut: A buffer accepting an error string upon error. -/// - versionOut: A buffer accepting a regex literal format -/// version. -/// - captureStructureOut: A buffer accepting a byte sequence representing the -/// capture structure. -/// - captureStructureSize: The size of the capture structure buffer. Must be -/// greater than or equal to `strlen(inputPtr)`. -@available(*, deprecated, message: "moving to SwiftCompilerModules") -func libswiftParseRegexLiteral( - _ inputPtr: UnsafePointer?, - _ errOut: UnsafeMutablePointer?>?, - _ versionOut: UnsafeMutablePointer?, - _ captureStructureOut: UnsafeMutableRawPointer?, - _ captureStructureSize: CUnsignedInt -) { - guard let s = inputPtr else { fatalError("Expected input param") } - guard let errOut = errOut else { fatalError("Expected error out param") } - guard let versionOut = versionOut else { - fatalError("Expected version out param") - } - - versionOut.pointee = currentRegexLiteralFormatVersion - - let str = String(cString: s) - do { - let ast = try parseWithDelimiters(str) - // Serialize the capture structure for later type inference. - if let captureStructureOut = captureStructureOut { - assert(captureStructureSize >= str.utf8.count) - let buffer = UnsafeMutableRawBufferPointer( - start: captureStructureOut, count: Int(captureStructureSize)) - ast.captureStructure.encode(to: buffer) - } - } catch { - errOut.pointee = copyCString( - "cannot parse regular expression: \(String(describing: error))") - } -} diff --git a/Tests/RegexTests/ParseTests.swift b/Tests/RegexTests/ParseTests.swift index 94c134853..e66078831 100644 --- a/Tests/RegexTests/ParseTests.swift +++ b/Tests/RegexTests/ParseTests.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -@testable import _RegexParser +@testable @_spi(CompilerInterface) import _RegexParser import XCTest @testable import _StringProcessing @@ -281,24 +281,20 @@ func delimiterLexingDiagnosticTest( } } -func libswiftDiagnosticMessageTest( - _ input: String, _ expectedErr: String, file: StaticString = #file, - line: UInt = #line +func compilerInterfaceDiagnosticMessageTest( + _ input: String, _ expectedErr: String, + file: StaticString = #file, line: UInt = #line ) { - var errPtr: UnsafePointer? - var version: CUnsignedInt = 0 - - libswiftParseRegexLiteral( - input, &errPtr, &version, /*captureStructure*/ nil, - /*captureStructureSize*/ 0 - ) - - guard let errPtr = errPtr else { - XCTFail("Unexpected test pass", file: file, line: line) - return + do { + let captureBuffer = UnsafeMutableRawBufferPointer(start: nil, count: 0) + _ = try swiftCompilerParseRegexLiteral( + input, captureBufferOut: captureBuffer) + XCTFail("Expected parse error", file: file, line: line) + } catch let error as CompilerParseError { + XCTAssertEqual(expectedErr, error.message, file: file, line: line) + } catch { + fatalError("Expected CompilerParseError") } - let err = String(cString: errPtr) - XCTAssertEqual(expectedErr, err, file: file, line: line) } extension RegexTests { @@ -2547,8 +2543,8 @@ extension RegexTests { delimiterLexingDiagnosticTest("#/\n#/#", .multilineClosingNotOnNewline) } - func testlibswiftDiagnostics() { - libswiftDiagnosticMessageTest( + func testCompilerInterfaceDiagnostics() { + compilerInterfaceDiagnosticMessageTest( "#/[x*/#", "cannot parse regular expression: expected ']'") } } From 2c386ef83157f0d3759eeb761c53f3ba8adfd730 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 28 Apr 2022 09:28:16 -0700 Subject: [PATCH 126/133] Add some comments --- .../_StringProcessing/PrintAsPattern.swift | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index 3ab00f15f..7b9dbc7c1 100644 --- a/Sources/_StringProcessing/PrintAsPattern.swift +++ b/Sources/_StringProcessing/PrintAsPattern.swift @@ -58,7 +58,7 @@ extension PrettyPrinter { // TODO: Handle global options... let node = ast.root.dslTreeNode - // If we have any named captures, create referencs to those above the regex. + // If we have any named captures, create references to those above the regex. let namedCaptures = node.getNamedCaptures() for namedCapture in namedCaptures { @@ -226,6 +226,23 @@ extension PrettyPrinter { var charMembers = "" + + // This iterates through all of the character class members collecting all + // of the members who can be stuffed into a singular '.anyOf(...)' vs. + // having multiple. This does alter the original representation, but the + // result is the same. For example: + // + // Convert: '[abc\d\Qxyz\E[:space:]def]' + // + // CharacterClass( + // .anyOf("abcxyzdef"), + // .digit, + // .whitespace + // ) + // + // This also allows us to determine if after collecting all of the members + // and stuffing them if we can just emit a standalone '.anyOf' instead of + // initializing a 'CharacterClass'. let nonCharMembers = ccc.members.filter { switch $0 { case let .atom(a): From b7fb965dc0c3a92b671fc5b9dc4c0dab5149d20c Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 28 Apr 2022 19:08:10 +0100 Subject: [PATCH 127/133] Replace opaque results with generic parameters in Algorithms.swift (#367) Work around the compiler bug rdar://92459215 by using generic parameters instead of opaque result types for a couple of methods. --- Sources/RegexBuilder/Algorithms.swift | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Sources/RegexBuilder/Algorithms.swift b/Sources/RegexBuilder/Algorithms.swift index f206ee768..f1f6d97a0 100644 --- a/Sources/RegexBuilder/Algorithms.swift +++ b/Sources/RegexBuilder/Algorithms.swift @@ -11,6 +11,11 @@ import _StringProcessing +// FIXME(rdar://92459215): We should be using 'some RegexComponent' instead of +// for the methods below that don't impose any additional +// requirements on the type. Currently the generic parameter is needed to work +// around a compiler issue. + extension BidirectionalCollection where SubSequence == Substring { /// Matches a regex in its entirety, where the regex is created by /// the given closure. @@ -94,10 +99,10 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: A collection of substrings, split from this collection's /// elements. @available(SwiftStdlib 5.7, *) - public func split( + public func split( maxSplits: Int = Int.max, omittingEmptySubsequences: Bool = true, - @RegexComponentBuilder separator: () -> some RegexComponent + @RegexComponentBuilder separator: () -> R ) -> [SubSequence] { split(separator: separator(), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) } @@ -191,11 +196,11 @@ where Self: BidirectionalCollection, SubSequence == Substring { /// - Returns: A new collection in which all matches for regex in `subrange` /// are replaced by `replacement`, using `content` to create the regex. @available(SwiftStdlib 5.7, *) - public func replacing( + public func replacing( with replacement: Replacement, subrange: Range, maxReplacements: Int = .max, - @RegexComponentBuilder content: () -> some RegexComponent + @RegexComponentBuilder content: () -> R ) -> Self where Replacement.Element == Element { replacing(content(), with: replacement, subrange: subrange, maxReplacements: maxReplacements) } @@ -213,10 +218,10 @@ where Self: BidirectionalCollection, SubSequence == Substring { /// - Returns: A new collection in which all matches for regex in `subrange` /// are replaced by `replacement`, using `content` to create the regex. @available(SwiftStdlib 5.7, *) - public func replacing( + public func replacing( with replacement: Replacement, maxReplacements: Int = .max, - @RegexComponentBuilder content: () -> some RegexComponent + @RegexComponentBuilder content: () -> R ) -> Self where Replacement.Element == Element { replacing(content(), with: replacement, maxReplacements: maxReplacements) } @@ -232,10 +237,10 @@ where Self: BidirectionalCollection, SubSequence == Substring { /// - content: A closure that returns the collection to search for /// and replace. @available(SwiftStdlib 5.7, *) - public mutating func replace( + public mutating func replace( with replacement: Replacement, maxReplacements: Int = .max, - @RegexComponentBuilder content: () -> some RegexComponent + @RegexComponentBuilder content: () -> R ) where Replacement.Element == Element { replace(content(), with: replacement, maxReplacements: maxReplacements) } From 838bdfea63b6d5aaa434ca906bc58684d1ec908b Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Thu, 28 Apr 2022 12:10:35 -0600 Subject: [PATCH 128/133] Simplify capture representations (#360) Introduce CaptureList, make CaptureStructure semi-vestigial --- .../PatternConverter/PatternConverter.swift | 10 - Sources/_RegexParser/Regex/AST/AST.swift | 6 - .../Regex/Parse/CaptureList.swift | 154 ++++++++++ .../Regex/Parse/CaptureStructure.swift | 290 +++--------------- .../_RegexParser/Regex/TreeProtocols.swift | 4 - Sources/_RegexParser/Utility/Misc.swift | 4 +- Sources/_StringProcessing/Compiler.swift | 2 +- .../_StringProcessing/Engine/MEBuilder.swift | 6 +- .../_StringProcessing/Engine/MECapture.swift | 2 +- .../_StringProcessing/Engine/MEProgram.swift | 2 +- .../Engine/Structuralize.swift | 81 +---- Sources/_StringProcessing/Executor.swift | 6 +- Sources/_StringProcessing/Regex/DSLTree.swift | 143 +++++---- Tests/RegexBuilderTests/RegexDSLTests.swift | 3 + Tests/RegexTests/CaptureTests.swift | 174 ++++++----- Tests/RegexTests/ParseTests.swift | 107 ++++--- 16 files changed, 457 insertions(+), 537 deletions(-) create mode 100644 Sources/_RegexParser/Regex/Parse/CaptureList.swift diff --git a/Sources/PatternConverter/PatternConverter.swift b/Sources/PatternConverter/PatternConverter.swift index f66204884..a10698526 100644 --- a/Sources/PatternConverter/PatternConverter.swift +++ b/Sources/PatternConverter/PatternConverter.swift @@ -30,9 +30,6 @@ struct PatternConverter: ParsableCommand { @Flag(help: "Whether to show canonical regex literal") var showCanonical: Bool = false - @Flag(help: "Whether to show capture structure") - var showCaptureStructure: Bool = false - @Flag(help: "Whether to skip result builder DSL") var skipDSL: Bool = false @@ -71,13 +68,6 @@ struct PatternConverter: ParsableCommand { print() } - if showCaptureStructure { - print("Capture structure:") - print() - print(ast.captureStructure) - print() - } - print() if !skipDSL { let render = ast.renderAsBuilderDSL( diff --git a/Sources/_RegexParser/Regex/AST/AST.swift b/Sources/_RegexParser/Regex/AST/AST.swift index eae393289..a7dcd2015 100644 --- a/Sources/_RegexParser/Regex/AST/AST.swift +++ b/Sources/_RegexParser/Regex/AST/AST.swift @@ -25,12 +25,6 @@ public struct AST: Hashable { extension AST { /// Whether this AST tree contains at least one capture nested inside of it. public var hasCapture: Bool { root.hasCapture } - - /// The capture structure of this AST tree. - public var captureStructure: CaptureStructure { - var constructor = CaptureStructure.Constructor(.flatten) - return root._captureStructure(&constructor) - } } extension AST { diff --git a/Sources/_RegexParser/Regex/Parse/CaptureList.swift b/Sources/_RegexParser/Regex/Parse/CaptureList.swift new file mode 100644 index 000000000..d112b2010 --- /dev/null +++ b/Sources/_RegexParser/Regex/Parse/CaptureList.swift @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +public struct CaptureList { + public var captures: [Capture] + + public init(_ s: S) where S.Element == Capture { + captures = Array(s) + } + + public mutating func append(_ c: Capture) { + captures.append(c) + } +} + +extension CaptureList { + public struct Capture { + public var name: String? + public var type: Any.Type? + public var optionalDepth: Int + + public init( + name: String? = nil, + type: Any.Type? = nil, + optionalDepth: Int + ) { + self.name = name + self.type = type + self.optionalDepth = optionalDepth + } + } +} + +// MARK: Generating from AST + +extension AST.Node { + public func _addCaptures( + to list: inout CaptureList, + optionalNesting nesting: Int + ) { + let addOptional = nesting+1 + switch self { + case let .alternation(a): + for child in a.children { + child._addCaptures(to: &list, optionalNesting: addOptional) + } + + case let .concatenation(c): + for child in c.children { + child._addCaptures(to: &list, optionalNesting: nesting) + } + + case let .group(g): + switch g.kind.value { + case .capture: + list.append(.init(optionalDepth: nesting)) + + case .namedCapture(let name): + list.append(.init(name: name.value, optionalDepth: nesting)) + + case .balancedCapture(let b): + list.append(.init(name: b.name?.value, optionalDepth: nesting)) + + default: break + } + g.child._addCaptures(to: &list, optionalNesting: nesting) + + case .conditional(let c): + switch c.condition.kind { + case .group(let g): + AST.Node.group(g)._addCaptures(to: &list, optionalNesting: nesting) + default: + break + } + + c.trueBranch._addCaptures(to: &list, optionalNesting: addOptional) + c.falseBranch._addCaptures(to: &list, optionalNesting: addOptional) + + case .quantification(let q): + var optNesting = nesting + if q.amount.value.bounds.atLeast == 0 { + optNesting += 1 + } + q.child._addCaptures(to: &list, optionalNesting: optNesting) + + case .absentFunction(let abs): + switch abs.kind { + case .expression(_, _, let child): + child._addCaptures(to: &list, optionalNesting: nesting) + case .clearer, .repeater, .stopper: + break + } + + case .quote, .trivia, .atom, .customCharacterClass, .empty: + break + } + } + + public var _captureList: CaptureList { + var caps = CaptureList() + self._addCaptures(to: &caps, optionalNesting: 0) + return caps + } +} + +extension AST { + /// Get the capture list for this AST + public var captureList: CaptureList { + root._captureList + } +} + +// MARK: Convenience for testing and inspection + +extension CaptureList.Capture: Equatable { + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.name == rhs.name && + lhs.optionalDepth == rhs.optionalDepth && + lhs.type == rhs.type + } +} +extension CaptureList: Equatable {} + +extension CaptureList.Capture: CustomStringConvertible { + public var description: String { + let typeStr: String + if let ty = type { + typeStr = "\(ty)" + } else { + typeStr = "Substring" + } + let suffix = String(repeating: "?", count: optionalDepth) + return typeStr + suffix + } +} +extension CaptureList: CustomStringConvertible { + public var description: String { + "(" + captures.map(\.description).joined(separator: ", ") + ")" + } +} + +extension CaptureList: ExpressibleByArrayLiteral { + public init(arrayLiteral elements: Capture...) { + self.init(elements) + } +} diff --git a/Sources/_RegexParser/Regex/Parse/CaptureStructure.swift b/Sources/_RegexParser/Regex/Parse/CaptureStructure.swift index 9cb31c7d9..6cd8001ba 100644 --- a/Sources/_RegexParser/Regex/Parse/CaptureStructure.swift +++ b/Sources/_RegexParser/Regex/Parse/CaptureStructure.swift @@ -9,258 +9,35 @@ // //===----------------------------------------------------------------------===// -// A tree representing the type of some captures. -public enum CaptureStructure: Equatable { +// TODO: Remove and directly serialize CaptureList instead + +// A tree representing the type of some captures, used for communication +// with the compiler. +enum CaptureStructure: Equatable { case atom(name: String? = nil, type: AnyType? = nil) indirect case optional(CaptureStructure) indirect case tuple([CaptureStructure]) - public static func tuple(_ children: CaptureStructure...) -> Self { + static func tuple(_ children: CaptureStructure...) -> Self { tuple(children) } - public static var empty: Self { + static var empty: Self { .tuple([]) } } -// TODO: Below are all flattening constructors. Instead create -// a builder/visitor that can store the structuralization -// approach - -extension CaptureStructure { - public struct Constructor { - var strategy: Strategy - - public init(_ strategy: Strategy = .flatten) { - guard strategy == .flatten else { - fatalError("TODO: adjust creator methods") - } - self.strategy = strategy - } - } -} - -extension CaptureStructure.Constructor { - public mutating func alternating( - _ children: C - ) -> CaptureStructure where C.Element: _TreeNode { - return children.map { - $0._captureStructure(&self) - }.reduce(.empty, +) - .map(CaptureStructure.optional) - } - public mutating func concatenating( - _ children: C - ) -> CaptureStructure where C.Element: _TreeNode { - return children.map { - $0._captureStructure(&self) - }.reduce(.empty, +) - } - - public mutating func grouping( - _ child: T, - as kind: AST.Group.Kind - ) -> CaptureStructure { - switch kind { - case .capture: - return capturing(child) - case .namedCapture(let name): - return capturing(name: name.value, child) - case .balancedCapture(let b): - return capturing(name: b.name?.value, child) - default: - precondition(!kind.isCapturing) - return child._captureStructure(&self) - } - } - - public mutating func capturing( - name: String? = nil, - _ child: T, - withType type: AnyType? = nil - ) -> CaptureStructure { - .atom(name: name, type: type) - + child._captureStructure(&self) - } - - // TODO: We'll likely want/need a generalization of - // conditional's condition kind. - public mutating func condition( - _ condition: AST.Conditional.Condition.Kind, - trueBranch: T, - falseBranch: T - ) -> CaptureStructure { - // A conditional's capture structure is effectively that of an alternation - // between the true and false branches. However the condition may also - // have captures in the case of a group condition. - var captures = CaptureStructure.empty - switch condition { - case .group(let g): - captures = captures + AST.Node.group(g)._captureStructure(&self) - default: - break - } - let branchCaptures = trueBranch._captureStructure(&self) + - falseBranch._captureStructure(&self) - return captures + branchCaptures.map(CaptureStructure.optional) - } - - public mutating func quantifying( - _ child: T, amount: AST.Quantification.Amount - ) -> CaptureStructure { - let result = child._captureStructure(&self) - return amount.bounds.atLeast == 0 - ? result.map(CaptureStructure.optional) : result - } - - // TODO: Will need to adjust for DSLTree support, and - // "absent" isn't the best name for these. - public mutating func absent( - _ kind: AST.AbsentFunction.Kind - ) -> CaptureStructure { - // Only the child of an expression absent function is relevant, as the - // other expressions don't actually get matched against. - switch kind { - case .expression(_, _, let child): - return child._captureStructure(&self) - case .clearer, .repeater, .stopper: - return .empty - } - } - -} - -extension AST.Node { - public func _captureStructure( - _ constructor: inout CaptureStructure.Constructor - ) -> CaptureStructure { - guard constructor.strategy == .flatten else { - fatalError("TODO") - } - - // Note: This implementation could be more optimized. - switch self { - case let .alternation(a): - return constructor.alternating(a.children) - - case let .concatenation(c): - return constructor.concatenating(c.children) - - case let .group(g): - return constructor.grouping(g.child, as: g.kind.value) - - case .conditional(let c): - return constructor.condition( - c.condition.kind, - trueBranch: c.trueBranch, - falseBranch: c.falseBranch) - - case .quantification(let q): - return constructor.quantifying( - q.child, amount: q.amount.value) - - case .absentFunction(let abs): - return constructor.absent(abs.kind) - - case .quote, .trivia, .atom, .customCharacterClass, .empty: - return .empty - } - } -} - -// MARK: - Combination and transformation - -extension CaptureStructure { - /// Returns a capture structure by concatenating any tuples in `self` and - /// `other`. - func concatenating(with other: CaptureStructure) -> CaptureStructure { - switch (self, other) { - // (T...) + (U...) ==> (T..., U...) - case let (.tuple(lhs), .tuple(rhs)): - return .tuple(lhs + rhs) - // T + () ==> T - case (_, .tuple(let rhs)) where rhs.isEmpty: - return self - // () + T ==> T - case (.tuple(let lhs), _) where lhs.isEmpty: - return other - // (T...) + U ==> (T..., U) - case let (.tuple(lhs), _): - return .tuple(lhs + [other]) - // T + (U...) ==> (T, U...) - case let (_, .tuple(rhs)): - return .tuple([self] + rhs) - // T + U ==> (T, U) - default: - return .tuple([self, other]) - } - } - - static func + ( - lhs: CaptureStructure, rhs: CaptureStructure - ) -> CaptureStructure { - lhs.concatenating(with: rhs) - } - - /// Returns a capture structure by transforming any tuple element of `self` - /// or transforming `self` directly if it is not a tuple. - func map( - _ transform: (CaptureStructure) -> CaptureStructure - ) -> CaptureStructure { - if case .tuple(let children) = self { - return .tuple(children.map(transform)) - } - return transform(self) - } -} - // MARK: - Common properties extension CaptureStructure { /// Returns a Boolean indicating whether the structure does not contain any /// captures. - public var isEmpty: Bool { + private var isEmpty: Bool { if case .tuple(let elements) = self, elements.isEmpty { return true } return false } - - public func type(withAtomType atomType: Any.Type) -> Any.Type { - switch self { - case .atom(_, type: nil): - return atomType - case .atom(_, type: let type?): - return type.base - case .optional(let child): - return TypeConstruction.optionalType(of: child.type(withAtomType: atomType)) - case .tuple(let children): - return TypeConstruction.tupleType(of: children.map { - $0.type(withAtomType: atomType) - }) - } - } - - public typealias DefaultAtomType = Substring - - public var type: Any.Type { - type(withAtomType: DefaultAtomType.self) - } - - public var atomType: AnyType { - switch self { - case .atom(_, type: nil): - return .init(Substring.self) - case .atom(_, type: let type?): - return type - case .optional(let child): - return child.atomType - case .tuple: - fatalError("Recursive nesting has no single atom type") - } - - } } // MARK: - Serialization @@ -280,7 +57,7 @@ extension CaptureStructure { private typealias SerializationVersion = UInt16 private static let currentSerializationVersion: SerializationVersion = 1 - public static func serializationBufferSize( + static func serializationBufferSize( forInputUTF8CodeUnitCount inputUTF8CodeUnitCount: Int ) -> Int { MemoryLayout.stride + inputUTF8CodeUnitCount + 1 @@ -302,7 +79,7 @@ extension CaptureStructure { /// /// - Parameter buffer: A buffer whose byte count is at least the byte count /// of the regular expression string that produced this capture structure. - public func encode(to buffer: UnsafeMutableRawBufferPointer) { + func encode(to buffer: UnsafeMutableRawBufferPointer) { assert(!buffer.isEmpty, "Buffer must not be empty") assert( buffer.count >= @@ -361,7 +138,7 @@ extension CaptureStructure { /// Creates a capture structure by decoding a serialized representation from /// the given buffer. - public init?(decoding buffer: UnsafeRawBufferPointer) { + init?(decoding buffer: UnsafeRawBufferPointer) { var scopes: [[CaptureStructure]] = [[]] var currentScope: [CaptureStructure] { get { scopes[scopes.endIndex - 1] } @@ -415,13 +192,13 @@ extension CaptureStructure { } extension CaptureStructure: CustomStringConvertible { - public var description: String { + var description: String { var printer = PrettyPrinter() _print(&printer) return printer.finish() } - private func _print(_ printer: inout PrettyPrinter) { + func _print(_ printer: inout PrettyPrinter) { switch self { case let .atom(name, type): let name = name ?? "" @@ -445,10 +222,41 @@ extension CaptureStructure: CustomStringConvertible { } } -extension CaptureStructure.Constructor { - public enum Strategy { - case flatten - case nest - // case drop(after: Int)... +extension AST { + /// The capture structure of this AST for compiler communication. + var captureStructure: CaptureStructure { + root._captureList._captureStructure(nestOptionals: true) + } +} + +// MARK: Convert CaptureList into CaptureStructure + +extension CaptureList { + func _captureStructure(nestOptionals: Bool) -> CaptureStructure { + if captures.isEmpty { return .empty } + if captures.count == 1 { + return captures.first!._captureStructure(nestOptionals: nestOptionals) + } + return .tuple(captures.map { + $0._captureStructure(nestOptionals: nestOptionals) + }) + } +} + +extension CaptureList.Capture { + func _captureStructure(nestOptionals: Bool) -> CaptureStructure { + if optionalDepth == 0 { + if let ty = type { + return .atom(name: name, type: .init(ty)) + } + return .atom(name: name) + } + var copy = self + copy.optionalDepth = 0 + var base = copy._captureStructure(nestOptionals: false) + for _ in 0..<(nestOptionals ? optionalDepth : 1) { + base = .optional(base) + } + return base } } diff --git a/Sources/_RegexParser/Regex/TreeProtocols.swift b/Sources/_RegexParser/Regex/TreeProtocols.swift index c14db65ce..7f1ccb5f7 100644 --- a/Sources/_RegexParser/Regex/TreeProtocols.swift +++ b/Sources/_RegexParser/Regex/TreeProtocols.swift @@ -2,10 +2,6 @@ public protocol _TreeNode { var children: [Self]? { get } - - func _captureStructure( - _: inout CaptureStructure.Constructor - ) -> CaptureStructure } extension _TreeNode { diff --git a/Sources/_RegexParser/Utility/Misc.swift b/Sources/_RegexParser/Utility/Misc.swift index bd9bc665e..d37dfbd4a 100644 --- a/Sources/_RegexParser/Utility/Misc.swift +++ b/Sources/_RegexParser/Utility/Misc.swift @@ -167,7 +167,7 @@ extension BinaryInteger { } /// A wrapper of an existential metatype, equatable and hashable by reference. -public struct AnyType: Equatable, Hashable { +public struct AnyType: Hashable { public var base: Any.Type public init(_ type: Any.Type) { @@ -182,3 +182,5 @@ public struct AnyType: Equatable, Hashable { hasher.combine(ObjectIdentifier(base)) } } + + diff --git a/Sources/_StringProcessing/Compiler.swift b/Sources/_StringProcessing/Compiler.swift index 96476f42b..47faa23ed 100644 --- a/Sources/_StringProcessing/Compiler.swift +++ b/Sources/_StringProcessing/Compiler.swift @@ -28,7 +28,7 @@ class Compiler { __consuming func emit() throws -> Program { // TODO: Handle global options var codegen = ByteCodeGen(options: options) - codegen.builder.captureStructure = tree.captureStructure + codegen.builder.captureList = tree.root._captureList try codegen.emitNode(tree.root) let program = try codegen.finish() return program diff --git a/Sources/_StringProcessing/Engine/MEBuilder.swift b/Sources/_StringProcessing/Engine/MEBuilder.swift index 2b38ace0a..cae8194bd 100644 --- a/Sources/_StringProcessing/Engine/MEBuilder.swift +++ b/Sources/_StringProcessing/Engine/MEBuilder.swift @@ -38,9 +38,7 @@ extension MEProgram where Input.Element: Hashable { // Special addresses or instructions var failAddressToken: AddressToken? = nil - // TODO: Should we have better API for building this up - // as we compile? - var captureStructure: CaptureStructure = .empty + var captureList = CaptureList() // Symbolic reference resolution var unresolvedReferences: [ReferenceID: [InstructionAddress]] = [:] @@ -353,7 +351,7 @@ extension MEProgram.Builder { staticTransformFunctions: transformFunctions, staticMatcherFunctions: matcherFunctions, registerInfo: regInfo, - captureStructure: captureStructure, + captureList: captureList, referencedCaptureOffsets: referencedCaptureOffsets, namedCaptureOffsets: namedCaptureOffsets) } diff --git a/Sources/_StringProcessing/Engine/MECapture.swift b/Sources/_StringProcessing/Engine/MECapture.swift index 807598637..e3a542c1e 100644 --- a/Sources/_StringProcessing/Engine/MECapture.swift +++ b/Sources/_StringProcessing/Engine/MECapture.swift @@ -142,7 +142,7 @@ extension Processor._StoredCapture: CustomStringConvertible { } } -struct CaptureList { +struct MECaptureList { var values: Array._StoredCapture> var referencedCaptureOffsets: [ReferenceID: Int] var namedCaptureOffsets: [String: Int] diff --git a/Sources/_StringProcessing/Engine/MEProgram.swift b/Sources/_StringProcessing/Engine/MEProgram.swift index 0bfa0ecba..8f1c721b0 100644 --- a/Sources/_StringProcessing/Engine/MEProgram.swift +++ b/Sources/_StringProcessing/Engine/MEProgram.swift @@ -34,7 +34,7 @@ struct MEProgram where Input.Element: Equatable { var enableTracing: Bool = false - let captureStructure: CaptureStructure + let captureList: CaptureList let referencedCaptureOffsets: [ReferenceID: Int] let namedCaptureOffsets: [String: Int] } diff --git a/Sources/_StringProcessing/Engine/Structuralize.swift b/Sources/_StringProcessing/Engine/Structuralize.swift index 12d2e1242..a8cfeb20c 100644 --- a/Sources/_StringProcessing/Engine/Structuralize.swift +++ b/Sources/_StringProcessing/Engine/Structuralize.swift @@ -1,78 +1,21 @@ @_implementationOnly import _RegexParser -extension CaptureStructure { - var optionalCount: Int { - switch self { - case .atom: return 0 - case .optional(let o): - return 1 + o.optionalCount - case .tuple: - // FIXME: Separate CaptureStructure and a component - fatalError("Recursive nesting") - @unknown default: - fatalError("Unknown default") - } - } - - // FIXME: Do it all in one pass, no need for all these - // intermediary arrays +extension CaptureList { func structuralize( - _ list: CaptureList, + _ list: MECaptureList, _ input: String - ) throws -> [StructuredCapture] { - - func mapCap( - _ cap: CaptureStructure, - _ storedCap: Processor._StoredCapture - ) -> StructuredCapture { - // TODO: CaptureList perhaps should store a - // metatype or relevant info... - let optCount = cap.optionalCount - - if cap.atomType.base == Substring.self { - // FIXME: What if a typed capture is Substring? - assert(!storedCap.hasValues) - - if let r = storedCap.latest { - return StructuredCapture( - optionalCount: optCount, - storedCapture: StoredCapture(range: r)) - } + ) -> [StructuredCapture] { + assert(list.values.count == captures.count) - return StructuredCapture( - optionalCount: optCount, - storedCapture: nil) - } + var result = [StructuredCapture]() + for (cap, meStored) in zip(self.captures, list.values) { + let stored = StoredCapture( + range: meStored.latest, value: meStored.latestValue) - guard (storedCap.isEmpty || storedCap.hasValues) else { - print(storedCap) - fatalError() - } - // TODO: assert types are the same, under all the - // optionals - - if let v = storedCap.latestValue { - return StructuredCapture( - optionalCount: optCount, - storedCapture: StoredCapture(range: storedCap.latest, value: v)) - } - return StructuredCapture( - optionalCount: optCount, - storedCapture: nil) - } - - switch self { - case let .tuple(values): - assert(list.values.count == values.count) - var result = Array() - for (cap, storedCap) in zip(values, list.values) { - result.append(mapCap(cap, storedCap)) - } - return result - - default: - assert(list.values.count == 1) - return [mapCap(self, list.values.first!)] + result.append(.init( + optionalCount: cap.optionalDepth, storedCapture: stored)) } + return result } } + diff --git a/Sources/_StringProcessing/Executor.swift b/Sources/_StringProcessing/Executor.swift index 6ebb93f5c..e44b110e5 100644 --- a/Sources/_StringProcessing/Executor.swift +++ b/Sources/_StringProcessing/Executor.swift @@ -35,15 +35,13 @@ struct Executor { return nil } - let capList = CaptureList( + let capList = MECaptureList( values: cpu.storedCaptures, referencedCaptureOffsets: engine.program.referencedCaptureOffsets, namedCaptureOffsets: engine.program.namedCaptureOffsets) - let capStruct = engine.program.captureStructure let range = inputRange.lowerBound.. CaptureStructure { - switch node { - case let .orderedChoice(children): - return constructor.alternating(children.map(_Tree.init)) - - case let .concatenation(children): - return constructor.concatenating(children.map(_Tree.init)) - - case let .capture(name, _, child): - if let type = child.valueCaptureType { - return constructor.capturing( - name: name, _Tree(child), withType: type) - } - return constructor.capturing(name: name, _Tree(child)) - - case let .nonCapturingGroup(kind, child): - assert(!kind.ast.isCapturing) - return constructor.grouping(_Tree(child), as: kind.ast) - - case let .conditional(cond, trueBranch, falseBranch): - return constructor.condition( - cond.ast, - trueBranch: _Tree(trueBranch), - falseBranch: _Tree(falseBranch)) - - case let .quantification(amount, _, child): - return constructor.quantifying( - Self(child), amount: amount.ast) - - case let .regexLiteral(re): - // TODO: Force a re-nesting? - return re.ast._captureStructure(&constructor) - - case let .absentFunction(abs): - return constructor.absent(abs.ast.kind) - - case let .convertedRegexLiteral(n, _): - // TODO: Switch nesting strategy? - return Self(n)._captureStructure(&constructor) - - case .matcher: - return .empty - - case .transform(_, let child): - return Self(child)._captureStructure(&constructor) - - case .customCharacterClass, .atom, .trivia, .empty, - .quotedLiteral, .consumer, .characterPredicate: - return .empty - } - } } @_spi(RegexBuilder) diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index b646f16f7..4e08ea103 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -570,6 +570,7 @@ class RegexDSLTests: XCTestCase { } let _: (Substring, Substring, Substring).Type = type(of: regex1).RegexOutput.self + let regex2 = Regex { OneOrMore("a") Capture { @@ -581,6 +582,7 @@ class RegexDSLTests: XCTestCase { } let _: (Substring, Substring, Int?).Type = type(of: regex2).RegexOutput.self + let regex3 = Regex { OneOrMore("a") Capture { @@ -593,6 +595,7 @@ class RegexDSLTests: XCTestCase { } let _: (Substring, Substring, Int, Double?).Type = type(of: regex3).RegexOutput.self + let regex4 = Regex { OneOrMore("a") Capture { diff --git a/Tests/RegexTests/CaptureTests.swift b/Tests/RegexTests/CaptureTests.swift index 7d4266071..b48e1f0a5 100644 --- a/Tests/RegexTests/CaptureTests.swift +++ b/Tests/RegexTests/CaptureTests.swift @@ -11,7 +11,42 @@ import XCTest @testable @_spi(RegexBuilder) import _StringProcessing -import _RegexParser +@testable import _RegexParser + + +extension CaptureList.Capture { + static var cap: Self { + return Self(optionalDepth: 0) + } + + static var opt: Self { + return Self(optionalDepth: 1) + } + static var opt_opt: Self { + return Self(optionalDepth: 2) + } + static var opt_opt_opt: Self { + return Self(optionalDepth: 3) + } + static var opt_opt_opt_opt: Self { + return Self(optionalDepth: 4) + } + static var opt_opt_opt_opt_opt: Self { + return Self(optionalDepth: 5) + } + static var opt_opt_opt_opt_opt_opt: Self { + return Self(optionalDepth: 6) + } + + static func named(_ name: String) -> Self { + return Self(name: name, optionalDepth: 0) + } +} +extension CaptureList { + static func caps(count: Int) -> Self { + Self(Array(repeating: .cap, count: count)) + } +} extension StructuredCapture { func formatStringCapture(input: String) -> String { @@ -109,36 +144,35 @@ func compile(_ ast: AST) -> Executor { func captureTest( _ regex: String, - _ expected: CaptureStructure, + _ expected: CaptureList, _ tests: (input: String, output: [StringCapture])..., skipEngine: Bool = false, file: StaticString = #file, line: UInt = #line ) { - let ast = try! parse(regex, .traditional) - let capStructure = ast.captureStructure - guard capStructure == expected else { + let capList = ast.root._captureList + guard capList == expected else { XCTFail(""" - Expected: - \(expected) - Actual: - \(capStructure) - """, - file: file, - line: line) + Expected: + \(expected) + Actual: + \(capList) + """, + file: file, + line: line) return } // Ensure DSLTree preserves literal captures - let dslCapStructure = ast.dslTree.captureStructure - guard dslCapStructure == capStructure else { + let dslCapList = ast.dslTree.root._captureList + guard dslCapList == capList else { XCTFail(""" DSLTree did not preserve structure: AST: - \(capStructure) + \(capList) DSLTree: - \(dslCapStructure) + \(dslCapList) """, file: file, line: line) @@ -192,168 +226,150 @@ extension RegexTests { func testLiteralStructuredCaptures() throws { captureTest( "abc", - .empty, + [], ("abc", [])) captureTest( "a(b)c", - .atom(), + [.cap], ("abc", ["b"])) captureTest( "a(b*)c", - .atom(), + [.cap], ("abc", ["b"]), ("ac", [""]), ("abbc", ["bb"])) captureTest( "a(b)*c", - .optional(.atom()), + [.opt], ("abc", [.some("b")]), ("ac", [.none]), ("abbc", [.some("b")])) captureTest( "a(b)+c", - .atom(), + [.cap], ("abc", ["b"]), ("abbc", ["b"])) captureTest( "a(b)?c", - .optional(.atom()), + [.opt], ("ac", [.none]), ("abc", [.some("b")])) captureTest( "(a)(b)(c)", - .tuple([.atom(),.atom(),.atom()]), + [.cap, .cap, .cap], ("abc", ["a", "b", "c"])) captureTest( "a|(b)", - .optional(.atom()), + [.opt], ("a", [.none]), ("b", [.some("b")])) captureTest( "(a)|(b)", - .tuple(.optional(.atom()), .optional(.atom())), + [.opt, .opt], ("a", [.some("a"), .none]), ("b", [.none, .some("b")])) captureTest( "((a)|(b))", - .tuple(.atom(), .optional(.atom()), .optional(.atom())), + [.cap, .opt, .opt], ("a", ["a", .some("a"), .none]), ("b", ["b", .none, .some("b")])) captureTest( "((a)|(b))?", - .tuple( - .optional(.atom()), - .optional(.optional(.atom())), - .optional(.optional(.atom()))), + [.opt, .opt_opt, .opt_opt], ("a", [.some("a"), .some(.some("a")), .some(.none)]), ("b", [.some("b"), .some(.none), .some(.some("b"))])) + // FIXME captureTest( "((a)|(b))*", - .tuple( - .optional(.atom()), - .optional(.optional(.atom())), - .optional(.optional(.atom()))), + [.opt, .opt_opt, .opt_opt], ("a", [.some("a"), .some(.some("a")), .some(.none)]), skipEngine: true) + // FIXME captureTest( "((a)|(b))+", - .tuple( - .atom(), - .optional(.atom()), - .optional(.atom())), + [.cap, .opt, .opt], // TODO: test cases skipEngine: true) + // FIXME captureTest( "(((a)|(b))*)", - .tuple( - .atom(), - .optional(.atom()), - .optional(.optional(.atom())), - .optional(.optional(.atom()))), + [.cap, .opt, .opt_opt, .opt_opt], // TODO: test cases skipEngine: true) - + // FIXME captureTest( "(((a)|(b))?)", - .tuple( - .atom(), - .optional(.atom()), - .optional(.optional(.atom())), - .optional(.optional(.atom()))), + [.cap, .opt, .opt_opt, .opt_opt], // TODO: test cases skipEngine: true) captureTest( "(a)", - .atom(), + [.cap], ("a", ["a"])) captureTest( "((a))", - .tuple([.atom(), .atom()]), + [.cap, .cap], ("a", ["a", "a"])) captureTest( "(((a)))", - .tuple([.atom(), .atom(), .atom()]), + [.cap, .cap, .cap], ("a", ["a", "a", "a"])) - - // broke + // FIXME captureTest( "((((a)*)?)*)?", - .tuple([ - .optional(.atom()), - .optional(.optional(.atom())), - .optional(.optional(.optional(.atom()))), - .optional(.optional(.optional(.optional(.atom())))), - ]), + [.opt, .opt_opt, .opt_opt_opt, .opt_opt_opt_opt], // TODO: test cases skipEngine: true) - captureTest( "a|(b*)", - .optional(.atom()), + [.opt], ("a", [.none]), ("", [.some("")]), ("b", [.some("b")]), ("bbb", [.some("bbb")])) + // FIXME captureTest( "a|(b)*", - .optional(.optional(.atom())), + [.opt_opt], ("a", [.none]), ("", [.some("")]), ("b", [.some("b")]), ("bbb", [.some("b")]), skipEngine: true) + // FIXME captureTest( "a|(b)+", - .optional(.atom()), + [.opt], ("a", [.none]), ("b", [.some("b")]), ("bbb", [.some("b")]), skipEngine: true) + // FIXME captureTest( "a|(b)?", - .optional(.optional(.atom())), + [.opt_opt], ("a", [.none]), ("", [.none]), ("b", [.some(.some("b"))]), @@ -361,78 +377,78 @@ extension RegexTests { captureTest( "a|(b|c)", - .optional(.atom()), + [.opt], ("a", [.none]), ("b", [.some("b")]), ("c", [.some("c")])) captureTest( "a|(b*|c)", - .optional(.atom()), + [.opt], ("a", [.none]), ("b", [.some("b")]), ("c", [.some("c")])) + // FIXME captureTest( "a|(b|c)*", - .optional(.optional(.atom())), + [.opt_opt], ("a", [.none]), ("", [.some("")]), ("b", [.some("b")]), ("bbb", [.some("b")]), skipEngine: true) + // FIXME captureTest( "a|(b|c)?", - .optional(.optional(.atom())), + [.opt_opt], ("a", [.none]), ("", [.none]), ("b", [.some(.some("b"))]), ("c", [.some(.some("c"))]), skipEngine: true) - captureTest( "a(b(c))", - .tuple(.atom(), .atom()), + [.cap, .cap], ("abc", ["bc", "c"])) captureTest( "a(b(c*))", - .tuple(.atom(), .atom()), + [.cap, .cap], ("ab", ["b", ""]), ("abc", ["bc", "c"]), ("abcc", ["bcc", "cc"])) captureTest( "a(b(c)*)", - .tuple(.atom(), .optional(.atom())), + [.cap, .opt], ("ab", ["b", .none]), ("abc", ["bc", .some("c")]), ("abcc", ["bcc", .some("c")])) captureTest( "a(b(c)?)", - .tuple(.atom(), .optional(.atom())), + [.cap, .opt], ("ab", ["b", .none]), ("abc", ["bc", .some("c")])) - captureTest( "a(b(c))*", - .tuple(.optional(.atom()), .optional(.atom())), + [.opt, .opt], ("a", [.none, .none]), ("abc", [.some("bc"), .some("c")]), ("abcbc", [.some("bc"), .some("c")])) captureTest( "a(b(c))?", - .tuple(.optional(.atom()), .optional(.atom())), + [.opt, .opt], ("a", [.none, .none]), ("abc", [.some("bc"), .some("c")])) -// TODO: "((a|b)*|c)*" -// TODO: "((a|b)|c)*" + // TODO: "((a|b)*|c)*" + // TODO: "((a|b)|c)*" } diff --git a/Tests/RegexTests/ParseTests.swift b/Tests/RegexTests/ParseTests.swift index e66078831..aeefe6477 100644 --- a/Tests/RegexTests/ParseTests.swift +++ b/Tests/RegexTests/ParseTests.swift @@ -39,7 +39,7 @@ class RegexTests: XCTestCase {} func parseTest( _ input: String, _ expectedAST: AST.Node, syntax: SyntaxOptions = .traditional, - captures expectedCaptures: CaptureStructure = .empty, + captures expectedCaptures: CaptureList = [], file: StaticString = #file, line: UInt = #line ) { @@ -52,7 +52,7 @@ func parseTest( func parseTest( _ input: String, _ expectedAST: AST, syntax: SyntaxOptions = .traditional, - captures expectedCaptures: CaptureStructure = .empty, + captures expectedCaptures: CaptureList = [], file: StaticString = #file, line: UInt = #line ) { @@ -68,7 +68,7 @@ func parseTest( file: file, line: line) return } - let captures = ast.captureStructure + let captures = ast.captureList guard captures == expectedCaptures else { XCTFail(""" @@ -78,13 +78,16 @@ func parseTest( file: file, line: line) return } + // Test capture structure round trip serialization. + let capStruct = captures._captureStructure(nestOptionals: true) let serializedCapturesSize = CaptureStructure.serializationBufferSize( forInputUTF8CodeUnitCount: input.utf8.count) let serializedCaptures = UnsafeMutableRawBufferPointer.allocate( byteCount: serializedCapturesSize, alignment: MemoryLayout.alignment) - captures.encode(to: serializedCaptures) + + capStruct.encode(to: serializedCaptures) guard let decodedCaptures = CaptureStructure( decoding: UnsafeRawBufferPointer(serializedCaptures) ) else { @@ -95,7 +98,7 @@ func parseTest( """) return } - guard decodedCaptures == captures else { + guard decodedCaptures == capStruct else { XCTFail(""" Expected captures: \(expectedCaptures) @@ -306,7 +309,7 @@ extension RegexTests { concat("a", "b", "c", "+", zeroOrMore(of: "d"))) parseTest( "a(b)", concat("a", capture("b")), - captures: .atom()) + captures: [.cap]) parseTest( "abc(?:de)+fghi*k|j", alt( @@ -332,15 +335,13 @@ extension RegexTests { concat( zeroOrMore(of: capture(atom(.any))), capture(zeroOrMore(of: atom(.any)))), - captures: .tuple([.optional(.atom()), .atom()])) + captures: [.opt, .cap]) parseTest( "((.))*((.)?)", concat( zeroOrMore(of: capture(capture(atom(.any)))), capture(zeroOrOne(of: capture(atom(.any))))), - captures: .tuple([ - .optional(.atom()), .optional(.atom()), .atom(), .optional(.atom()) - ])) + captures: [.opt, .opt, .cap, .opt]) parseTest( #"abc\d"#, concat("a", "b", "c", escaped(.decimalDigit))) @@ -353,33 +354,33 @@ extension RegexTests { parseTest( "(a|b)c", concat(capture(alt("a", "b")), "c"), - captures: .atom()) + captures: [.cap]) parseTest( "(a)|b", alt(capture("a"), "b"), - captures: .optional(.atom())) + captures: [.opt]) parseTest( "(a)|(b)|c", alt(capture("a"), capture("b"), "c"), - captures: .tuple(.optional(.atom()), .optional(.atom()))) + captures: [.opt, .opt]) parseTest( "((a|b))c", concat(capture(capture(alt("a", "b"))), "c"), - captures: .tuple([.atom(), .atom()])) + captures: [.cap, .cap]) parseTest( "(?:((a|b)))*?c", concat(quant( .zeroOrMore, .reluctant, nonCapture(capture(capture(alt("a", "b"))))), "c"), - captures: .tuple(.optional(.atom()), .optional(.atom()))) + captures: [.opt, .opt]) parseTest( "(a)|b|(c)d", alt(capture("a"), "b", concat(capture("c"), "d")), - captures: .tuple([.optional(.atom()), .optional(.atom())])) + captures: [.opt, .opt]) // Alternations with empty branches are permitted. parseTest("|", alt(empty(), empty())) - parseTest("(|)", capture(alt(empty(), empty())), captures: .atom()) + parseTest("(|)", capture(alt(empty(), empty())), captures: [.cap]) parseTest("a|", alt("a", empty())) parseTest("|b", alt(empty(), "b")) parseTest("|b|", alt(empty(), "b", empty())) @@ -764,32 +765,32 @@ extension RegexTests { parseTest( #"a(?