diff --git a/.gitignore b/.gitignore index a7e7e4d09..ff85b9fa3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ .DS_Store +# The current toolchain is dumping files in the package root, rude +*.emit-module.* + # Xcode # # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 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 new file mode 100644 index 000000000..5f526f963 --- /dev/null +++ b/Documentation/Evolution/ProposalOverview.md @@ -0,0 +1,56 @@ + +# Regex Proposals + +## Regex Type and Overview + +- [Second review](https://forums.swift.org/t/se-0350-second-review-regex-type-and-overview/56886) +- [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. + + +## Run-time Regex Construction + +- [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. + +Covers the "interior" syntax, extended syntaxes, run-time construction of a regex from a string, and details of `AnyRegexOutput`. + +## Regex Literals + +- [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) + + +## 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 `CustomConsumingRegexComponent`, which is a monadic-parser style interface for external parsers to be used as components of a regex. + +## Unicode for String Processing + +- [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 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/RegexBuilderDSL.md b/Documentation/Evolution/RegexBuilderDSL.md index f0a477644..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** @@ -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 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/RegexLiterals.md b/Documentation/Evolution/RegexLiterals.md new file mode 100644 index 000000000..3643590d4 --- /dev/null +++ b/Documentation/Evolution/RegexLiterals.md @@ -0,0 +1,389 @@ +# Regex Literals + +- Authors: [Hamish Knight](https://github.com/hamishknight), [Michael Ilseman](https://github.com/milseman), [David Ewing](https://github.com/DaveEwing) + +## Introduction + +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 + +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+(.*)"# +let regex = try! Regex(pattern) +// regex: Regex +``` + +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 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 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 + +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. 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 `#/.../#`. + +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. + +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 for extracting a currency (dollars or pounds) and amount from input +// with precisely the form /[$£]\d+\.\d{2}/ +let regex = Regex { + Capture { /[$£]/ } + TryCapture { + /\d+/ + "." + /\d{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. + +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. + +## Detailed design + +### 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: + +```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 (String(match.identifier), hex) +} +``` + +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 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 `#` 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 + (? [^/]+) + /vmlinuz # The kernel +#/ +// regex: Regex<(Substring, subpath: Substring)> +``` + +#### 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 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: + +```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+/ +// 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 `#/.../#`. + +#### 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 `#` 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 + +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. + +A parsing conflict does however arise when a block comment surrounds a regex literal ending with `*`, for example: + + ```swift + /* + let regex = /[0-9]*/ + */ + ``` + +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 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 + +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 + +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 +let digit = Regex { + TryCapture(OneOrMore(.digit)) { Int($0) } +} +// Matches against + (' + ' | ' - ') + +let regex = Regex { + digit + / [+-] / + digit +} +``` + +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 +let regex = Regex { + digit + /\ [+-] / + digit +} +``` + +or extended literal must be used, e.g: + +```swift +let regex = Regex { + digit + #/ [+-] /# + digit +} +``` + +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] +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 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 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. + +#### Prefix operators containing `/` + +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^/ +``` + +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() +``` + +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 + +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(/, /) + +// 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) + +// 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 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: + +```swift +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 `)`. + + + +## 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 + +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 + +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'...'` + +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. 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. 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 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'...'` + +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 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. + +### Magic literal `#regex(...)` + +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 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 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. + +### Shortened magic literal `#(...)` + +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. + +```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 and other editor features for the regex syntax. +- 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. + +### No custom literal + +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. +- 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 + +[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/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 diff --git a/Documentation/Evolution/RegexSyntax.md b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md similarity index 83% rename from Documentation/Evolution/RegexSyntax.md rename to Documentation/Evolution/RegexSyntaxRunTimeConstruction.md index faa327176..bee7bbf03 100644 --- a/Documentation/Evolution/RegexSyntax.md +++ b/Documentation/Evolution/RegexSyntaxRunTimeConstruction.md @@ -1,36 +1,66 @@ - -# Run-time Regex Construction +# 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 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 [SE-0350 Regex Type and Overview][overview] and each individual component is tracked in [Pitch and Proposal Status][pitches]. ## 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, such as the need to translate between `NSRange` and `Range`. -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. +```swift +let pattern = #"(\w+)\s\s+(\S+)\s\s+((?:(?!\s\s).)*)\s\s+(.*)"# +let nsRegEx = try! NSRegularExpression(pattern: pattern) + +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(pattern) +// regex: Regex + +let regex: Regex<(Substring, Substring, Substring, Substring, Substring)> = + try! Regex(pattern) +``` ### Syntax @@ -51,11 +81,101 @@ 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(_ 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(_ 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 + + 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? +} +``` + +We propose adding API to query and access captures by name in an existentially typed regex match: -We propose the following syntax for regex. +```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 @@ -221,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 @@ -234,7 +354,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 '}' @@ -291,7 +411,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` @@ -433,6 +553,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 @@ -762,7 +883,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 @@ -827,6 +964,12 @@ We are deferring runtime support for callouts from regex literals as future work ## Alternatives Considered +### 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. + +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 @@ -866,3 +1009,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-evolution/blob/main/proposals/0350-regex-type-overview.md +[pitches]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/ProposalOverview.md + + + + diff --git a/Documentation/Evolution/RegexTypeOverview.md b/Documentation/Evolution/RegexTypeOverview.md index 504111181..94230d724 100644 --- a/Documentation/Evolution/RegexTypeOverview.md +++ b/Documentation/Evolution/RegexTypeOverview.md @@ -1,7 +1,11 @@ - # Regex Type and Overview -- Authors: [Michael Ilseman](https://github.com/milseman) and the Standard Library Team +* 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 @@ -14,7 +18,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. @@ -135,11 +139,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]. @@ -208,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) @@ -225,9 +229,9 @@ 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: +`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? { @@ -278,14 +282,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). @@ -301,7 +305,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" @@ -310,12 +314,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 +329,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 +348,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. } @@ -385,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. @@ -423,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 `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 @@ -482,6 +490,23 @@ 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. + +### 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). @@ -491,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. `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. @@ -540,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 +- `CustomConsumingRegexComponent` 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/issues/107 +[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 9454396ce..58426c145 100644 --- a/Documentation/Evolution/StringProcessingAlgorithms.md +++ b/Documentation/Evolution/StringProcessingAlgorithms.md @@ -8,13 +8,13 @@ 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 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://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 -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." @@ -31,7 +31,7 @@ while let r = str.range(of: "banana", options: [], range: idx.. @@ -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 `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) + 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)) + Capture(.localizedCurrency(code: "USD").sign(strategy: .accounting)) } let amount: [Decimal] = statement.matches(of: currencyRegex).map(\.result.1) @@ -162,32 +162,59 @@ 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` | +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 +## Detailed design -### `CustomMatchingRegexComponent` +### `CustomConsumingRegexComponent` -`CustomMatchingRegexComponent` 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 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 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: /// - 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 - ) -> (upperBound: String.Index, match: Match)? + ) throws -> (upperBound: String.Index, match: Match)? } ``` @@ -197,8 +224,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 : CustomConsumingRegexComponent { + public func consuming( _ input: String, startingAt index: String.Index, in bounds: Range @@ -214,17 +241,19 @@ 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")) } ``` - +
-### 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 @@ -232,35 +261,80 @@ 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 +} +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 } +``` + +We propose a regex-taking variant over string types (those that produce a `Substring` upon slicing). -extension BidirectionalCollection where SubSequence == Substring { +```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: R) -> Bool + 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. + /// + /// - 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 } ``` #### 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: R) -> Bool + 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. + /// + /// - 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 } ``` #### 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 @@ -279,7 +353,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 { @@ -288,7 +362,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 { @@ -297,44 +371,78 @@ 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 } +``` -extension BidirectionalCollection where SubSequence == Substring { +We propose regex-taking variants for string types: + +```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: R) -> SubSequence + public func trimmingPrefix(_ regex: some RegexComponent) -> SubSequence } -extension RangeReplaceableCollection - where Self: BidirectionalCollection, SubSequence == Substring -{ +// 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. + /// + /// - 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 +} + +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: R) + 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. + /// + /// - 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 + ) } ``` #### 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 @@ -342,8 +450,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 { @@ -352,22 +460,42 @@ 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 { +We propose a regex-taking variant for string types. + +```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: R) -> Range? + 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. + /// + /// - 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? } ``` #### 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 @@ -375,45 +503,133 @@ 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 { +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: R) -> some Collection> + 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. + /// + /// - 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> } ``` -#### First match +#### 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) -> RegexMatch? + 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. + /// + /// - 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? + + /// 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 + ) -> Regex.Match? + + /// 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 + ) -> Regex.Match? } ``` #### 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> + 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. + /// + /// - 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> } ``` #### 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 @@ -425,14 +641,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`. - public func replacing( - _ other: S, + /// `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 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. /// - Parameters: @@ -442,25 +703,29 @@ 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: /// - 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: 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 } +``` + +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. @@ -472,13 +737,13 @@ 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( - _ regex: R, + public func replacing( + _ r: some RegexComponent, with replacement: Replacement, 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: @@ -488,12 +753,12 @@ 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( - _ regex: R, + 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: @@ -501,112 +766,417 @@ 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( - _ regex: R, + 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. - /// - 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: (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. - /// - 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: (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. - /// - 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: (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. + /// + /// - 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. + 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 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. + public func replacing( + with replacement: Replacement, + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> some RegexComponent + ) -> Self where Replacement.Element == Element + + /// 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. + public mutating func replace( + with replacement: Replacement, + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> some RegexComponent + ) 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. + /// + /// - 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`. + 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 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`. + public func replacing( + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> R, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows -> Self where Replacement.Element == Element + + /// 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. + public mutating func replace( + maxReplacements: Int = .max, + @RegexComponentBuilder content: () -> R, + with replacement: (Regex.Match) throws -> Replacement ) rethrows where Replacement.Element == Element } ``` #### 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, - /// 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 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 +} +``` + +And a regex-taking variant for string types: -extension BidirectionalCollection where SubSequence == Substring { +```swift +extension Collection 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 +} + +// 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. + /// + /// - 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. + public func split( + maxSplits: Int = Int.max, + omittingEmptySubsequences: Bool = true, + @RegexComponentBuilder separator: () -> some RegexComponent + ) -> 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 } ``` +### 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 +#### 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 + +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. + + +### 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 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/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/Package.swift b/Package.swift index e95d98b67..f8162e762 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,51 +53,63 @@ 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: [ + .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) + ]), .testTarget( name: "RegexBuilderTests", dependencies: ["_StringProcessing", "RegexBuilder"], swiftSettings: [ - .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]) + .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), + .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) ]), - .target( + .testTarget( name: "Prototypes", - dependencies: ["_RegexParser", "_StringProcessing"]), + dependencies: ["_RegexParser", "_StringProcessing"], + 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"]) - ]), + name: "Exercises", + dependencies: ["_RegexParser", "_StringProcessing", "RegexBuilder"], + swiftSettings: [ + .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), + .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) + ]), .testTarget( - name: "ExercisesTests", - dependencies: ["Exercises"]), + name: "ExercisesTests", + dependencies: ["Exercises"], + swiftSettings: [ + .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) + ]) ] ) - 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. 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/Exercises/Participants/RegexParticipant.swift b/Sources/Exercises/Participants/RegexParticipant.swift index a40de3953..627f9583b 100644 --- a/Sources/Exercises/Participants/RegexParticipant.swift +++ b/Sources/Exercises/Participants/RegexParticipant.swift @@ -62,17 +62,17 @@ private func extractFromCaptures( private func graphemeBreakPropertyData( forLine line: String, using regex: RP -) -> GraphemeBreakEntry? where RP.Output == (Substring, Substring, Substring?, Substring) { - line.matchWhole(regex).map(\.output).flatMap(extractFromCaptures) +) -> GraphemeBreakEntry? where RP.RegexOutput == (Substring, Substring, Substring?, Substring) { + line.wholeMatch(of: regex).map(\.output).flatMap(extractFromCaptures) } 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( + #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, + as: (Substring, Substring, Substring?, Substring).self) + return graphemeBreakPropertyData(forLine: line, using: regex) } // MARK: - Builder DSL @@ -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/PatternConverter/PatternConverter.swift b/Sources/PatternConverter/PatternConverter.swift index ff47e4be2..a10698526 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 { @@ -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/RegexBuilder/Algorithms.swift b/Sources/RegexBuilder/Algorithms.swift new file mode 100644 index 000000000..f1f6d97a0 --- /dev/null +++ b/Sources/RegexBuilder/Algorithms.swift @@ -0,0 +1,315 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// 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. + /// + /// - 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: () -> R + ) -> [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: () -> R + ) -> 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: () -> R + ) -> 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: () -> R + ) 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/Anchor.swift b/Sources/RegexBuilder/Anchor.swift index ba910bd30..ae66310af 100644 --- a/Sources/RegexBuilder/Anchor.swift +++ b/Sources/RegexBuilder/Anchor.swift @@ -9,9 +9,16 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser @_spi(RegexBuilder) import _StringProcessing +/// A regex component that matches a specific condition at a particular position +/// in an input string. +/// +/// You can use anchors to guarantee that a match only occurs at certain points +/// in an input string, such as at the beginning of the string or at the end of +/// a line. +@available(SwiftStdlib 5.7, *) public struct Anchor { internal enum Kind { case startOfSubject @@ -28,49 +35,48 @@ public struct Anchor { var isInverted: Bool = false } +@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))) } } // MARK: - Public API +@available(SwiftStdlib 5.7, *) extension Anchor { + /// An anchor that matches at the start of the input string. + /// + /// This anchor is equivalent to `\A` in regex syntax. public static var startOfSubject: Anchor { Anchor(kind: .startOfSubject) } - + + /// An anchor that matches at the end of the input string or at the end of + /// the line immediately before the the end of the string. + /// + /// This anchor is equivalent to `\Z` in regex syntax. public static var endOfSubjectBeforeNewline: Anchor { Anchor(kind: .endOfSubjectBeforeNewline) } - + + /// An anchor that matches at the end of the input string. + /// + /// This anchor is equivalent to `\z` in regex syntax. public static var endOfSubject: Anchor { Anchor(kind: .endOfSubject) } @@ -80,26 +86,53 @@ extension Anchor { // Anchor(kind: resetStartOfMatch) // } + /// An anchor that matches at the first position of a match in the input + /// string. public static var firstMatchingPositionInSubject: Anchor { Anchor(kind: .firstMatchingPositionInSubject) } + /// An anchor that matches at a grapheme cluster boundary. + /// + /// This anchor is equivalent to `\y` in regex syntax. public static var textSegmentBoundary: Anchor { Anchor(kind: .textSegmentBoundary) } + /// An anchor that matches at the start of a line, including the start of + /// the input string. + /// + /// This anchor is equivalent to `^` in regex syntax when the `m` option + /// has been enabled or `anchorsMatchLineEndings(true)` has been called. public static var startOfLine: Anchor { Anchor(kind: .startOfLine) } + /// An anchor that matches at the end of a line, including at the end of + /// the input string. + /// + /// This anchor is equivalent to `$` in regex syntax when the `m` option + /// has been enabled or `anchorsMatchLineEndings(true)` has been called. public static var endOfLine: Anchor { Anchor(kind: .endOfLine) } + /// An anchor that matches at a word boundary. + /// + /// Word boundaries are identified using the Unicode default word boundary + /// algorithm by default. To specify a different word boundary algorithm, + /// see the `RegexComponent.wordBoundaryKind(_:)` method. + /// + /// This anchor is equivalent to `\b` in regex syntax. public static var wordBoundary: Anchor { Anchor(kind: .wordBoundary) } + /// The inverse of this anchor, which matches at every position that this + /// anchor does not. + /// + /// For the `wordBoundary` and `textSegmentBoundary` anchors, the inverted + /// version corresponds to `\B` and `\Y`, respectively. public var inverted: Anchor { var result = self result.isInverted.toggle() @@ -107,6 +140,14 @@ extension Anchor { } } +/// A regex component that allows a match to continue only if its contents +/// match at the given location. +/// +/// A lookahead is a zero-length assertion that its included regex matches at +/// a particular position. Lookaheads do not advance the overall matching +/// position in the input string — once a lookahead succeeds, matching continues +/// in the regex from the same position. +@available(SwiftStdlib 5.7, *) public struct Lookahead: _BuiltinRegexComponent { public var regex: Regex @@ -114,19 +155,48 @@ public struct Lookahead: _BuiltinRegexComponent { self.regex = regex } + /// Creates a lookahead from the given regex component. public init( - _ component: R, - negative: Bool = false - ) where R.Output == Output { - self.init(node: .nonCapturingGroup( - negative ? .negativeLookahead : .lookahead, component.regex.root)) + _ component: R + ) where R.RegexOutput == Output { + self.init(node: .nonCapturingGroup(.lookahead, component.regex.root)) } + + /// Creates a lookahead from the regex generated by the given builder closure. + public init( + @RegexComponentBuilder _ component: () -> R + ) where R.RegexOutput == Output { + self.init(node: .nonCapturingGroup(.lookahead, component().regex.root)) + } +} +/// A regex component that allows a match to continue only if its contents +/// do not match at the given location. +/// +/// A negative lookahead is a zero-length assertion that its included regex +/// does not match at a particular position. Lookaheads do not advance the +/// overall matching position in the input string — once a lookahead succeeds, +/// matching continues in the regex from the same position. +@available(SwiftStdlib 5.7, *) +public struct NegativeLookahead: _BuiltinRegexComponent { + public var regex: Regex + + init(_ regex: Regex) { + self.regex = regex + } + + /// Creates a negative lookahead from the given regex component. + public init( + _ component: R + ) where R.RegexOutput == Output { + self.init(node: .nonCapturingGroup(.negativeLookahead, component.regex.root)) + } + + /// Creates a negative lookahead from the regex generated by the given builder + /// closure. public init( - negative: Bool = false, @RegexComponentBuilder _ component: () -> R - ) where R.Output == Output { - self.init(node: .nonCapturingGroup( - negative ? .negativeLookahead : .lookahead, component().regex.root)) + ) where R.RegexOutput == Output { + self.init(node: .nonCapturingGroup(.negativeLookahead, component().regex.root)) } } 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 new file mode 100644 index 000000000..3a96ba363 --- /dev/null +++ b/Sources/RegexBuilder/CharacterClass.swift @@ -0,0 +1,178 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +@_implementationOnly import _RegexParser +@_spi(RegexBuilder) import _StringProcessing + +@available(SwiftStdlib 5.7, *) +public struct CharacterClass { + internal var ccc: DSLTree.CustomCharacterClass + + init(_ ccc: DSLTree.CustomCharacterClass) { + self.ccc = ccc + } + + init(unconverted model: _CharacterClassModel) { + guard let ccc = model.makeDSLTreeCharacterClass() else { + fatalError("Unsupported character class") + } + self.ccc = ccc + } +} + +@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)])) + } + + public static var anyGrapheme: CharacterClass { + .init(unconverted: .anyGrapheme) + } + + public static var anyUnicodeScalar: CharacterClass { + .init(unconverted: .anyUnicodeScalar) + } + + 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) + } +} + +@available(SwiftStdlib 5.7, *) +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 +@available(SwiftStdlib 5.7, *) +extension CharacterClass { + public static func generalCategory(_ category: Unicode.GeneralCategory) -> CharacterClass { + return CharacterClass(.generalCategory(category)) + } +} + +/// 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)) + let ccc = DSLTree.CustomCharacterClass(members: [range], isInverted: false) + return CharacterClass(ccc) +} + +/// 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 { + let range: DSLTree.CustomCharacterClass.Member = .range(.scalar(lhs), .scalar(rhs)) + let ccc = DSLTree.CustomCharacterClass(members: [range], isInverted: false) + return CharacterClass(ccc) +} + +// MARK: - Set algebra methods + +@available(SwiftStdlib 5.7, *) +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)) + } + } +} + +@available(SwiftStdlib 5.7, *) +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/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 80662be41..10590fb74 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -9,29 +9,70 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser @_spi(RegexBuilder) import _StringProcessing +@available(SwiftStdlib 5.7, *) extension Regex { public init( @RegexComponentBuilder _ content: () -> Content - ) where Content.Output == Output { + ) where Content.RegexOutput == Output { self = content().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) + init(_ regex: Regex) } +@available(SwiftStdlib 5.7, *) extension _BuiltinRegexComponent { init(node: DSLTree.Node) { self.init(Regex(node: node)) } } +// MARK: - Primitive regex components + +@available(SwiftStdlib 5.7, *) +extension String: RegexComponent { + public typealias Output = Substring + + public var regex: Regex { + .init(node: .quotedLiteral(self)) + } +} + +@available(SwiftStdlib 5.7, *) +extension Substring: RegexComponent { + public typealias Output = Substring + + public var regex: Regex { + .init(node: .quotedLiteral(String(self))) + } +} + +@available(SwiftStdlib 5.7, *) +extension Character: RegexComponent { + public typealias Output = Substring + + public var regex: Regex { + .init(node: .atom(.char(self))) + } +} + +@available(SwiftStdlib 5.7, *) +extension UnicodeScalar: RegexComponent { + public typealias Output = Substring + + public var regex: Regex { + .init(node: .atom(.scalar(self))) + } +} + // MARK: - Combinators // MARK: Concatenation @@ -53,74 +94,40 @@ extension _BuiltinRegexComponent { // Note: Quantifiers are currently gyb'd. -/// Specifies how much to attempt to match when using a quantifier. -public struct QuantificationBehavior { - internal enum Kind { - case eagerly - case reluctantly - case possessively - } - - var kind: Kind - - internal var astKind: AST.Quantification.Kind { - 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. + // 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, - _ 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.dslTreeKind) } ?? .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(range.lowerBound), .default, node) case (0, _): // 0..: _BuiltinRegexComponent { public var regex: Regex @@ -132,6 +139,7 @@ public struct OneOrMore: _BuiltinRegexComponent { // Variadics.swift. } +@available(SwiftStdlib 5.7, *) public struct ZeroOrMore: _BuiltinRegexComponent { public var regex: Regex @@ -143,6 +151,7 @@ public struct ZeroOrMore: _BuiltinRegexComponent { // Variadics.swift. } +@available(SwiftStdlib 5.7, *) public struct Optionally: _BuiltinRegexComponent { public var regex: Regex @@ -154,6 +163,7 @@ public struct Optionally: _BuiltinRegexComponent { // Variadics.swift. } +@available(SwiftStdlib 5.7, *) public struct Repeat: _BuiltinRegexComponent { public var regex: Regex @@ -179,12 +189,13 @@ public struct Repeat: _BuiltinRegexComponent { // ) -> R where R.Match == (W, C...) // } +@available(SwiftStdlib 5.7, *) @resultBuilder public struct AlternationBuilder { @_disfavoredOverload public static func buildPartialBlock( first component: R - ) -> ChoiceOf { + ) -> ChoiceOf { .init(component.regex) } @@ -201,6 +212,7 @@ public struct AlternationBuilder { } } +@available(SwiftStdlib 5.7, *) public struct ChoiceOf: _BuiltinRegexComponent { public var regex: Regex @@ -215,6 +227,7 @@ public struct ChoiceOf: _BuiltinRegexComponent { // MARK: - Capture +@available(SwiftStdlib 5.7, *) public struct Capture: _BuiltinRegexComponent { public var regex: Regex @@ -225,6 +238,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 @@ -237,8 +251,11 @@ 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 @@ -249,6 +266,8 @@ public struct Local: _BuiltinRegexComponent { // MARK: - Backreference +@available(SwiftStdlib 5.7, *) +/// A backreference. public struct Reference: RegexComponent { let id = ReferenceID() @@ -259,6 +278,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 deleted file mode 100644 index ac07ec0b8..000000000 --- a/Sources/RegexBuilder/Match.swift +++ /dev/null @@ -1,40 +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 - -extension String { - public func matchWhole( - @RegexComponentBuilder _ content: () -> R - ) -> Regex.Match? { - matchWhole(content()) - } - - public func matchPrefix( - @RegexComponentBuilder _ content: () -> R - ) -> Regex.Match? { - matchPrefix(content()) - } -} - -extension Substring { - public func matchWhole( - @RegexComponentBuilder _ content: () -> R - ) -> Regex.Match? { - matchWhole(content()) - } - - public func matchPrefix( - @RegexComponentBuilder _ content: () -> R - ) -> Regex.Match? { - matchPrefix(content()) - } -} diff --git a/Sources/RegexBuilder/Variadics.swift b/Sources/RegexBuilder/Variadics.swift index 989e5d463..f06978c8b 100644 --- a/Sources/RegexBuilder/Variadics.swift +++ b/Sources/RegexBuilder/Variadics.swift @@ -11,1728 +11,2003 @@ // BEGIN AUTO-GENERATED CONTENT -import _RegexParser @_spi(RegexBuilder) import _StringProcessing +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0)> where R0.Output == W0, R1.Output == (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 { - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1)> where R0.Output == W0, R1.Output == (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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - 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.Output == W0, R1.Output == (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 { - 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.Output == W0, R1.Output == (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 { - public static func buildPartialBlock( + public static func buildPartialBlock( accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1)> where R0.Output == (W0, C0), R1.Output == (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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - 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.Output == (W0, C0), R1.Output == (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 { - 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.Output == (W0, C0), R1.Output == (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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - 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.Output == (W0, C0, C1), R1.Output == (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 { - 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.Output == (W0, C0, C1), R1.Output == (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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - 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.Output == (W0, C0, C1, C2), R1.Output == (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 { - 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.Output == (W0, C0, C1, C2), R1.Output == (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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - 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.Output == (W0, C0, C1, C2, C3), R1.Output == (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 { - 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.Output == (W0, C0, C1, C2, C3), R1.Output == (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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - 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.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (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 { - 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.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (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 { - public static func buildPartialBlock( + 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, 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 { - public static func buildPartialBlock( + 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, 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 { - 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.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (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 { - 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.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (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 { - public static func buildPartialBlock( + 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, 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 { - 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.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (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 { - 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.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (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 { - 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.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Output == (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 { - 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.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Output == (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 { - 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.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.Output == (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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { + @available(SwiftStdlib 5.7, *) 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)) } } +@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.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)) } } +@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.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)) } } +@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.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)) } } +@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.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)) } } +@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.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)) } } +@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.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)) } } +@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.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)) } } +@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.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)) } } +@available(SwiftStdlib 5.7, *) extension Optionally { @_disfavoredOverload public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == Substring { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) where RegexOutput == Substring { + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Optionally { @_disfavoredOverload public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == Substring { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + ) where RegexOutput == Substring { + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } +@available(SwiftStdlib 5.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, *) extension ZeroOrMore { @_disfavoredOverload public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == Substring { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) where RegexOutput == Substring { + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { @_disfavoredOverload public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == Substring { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + ) where RegexOutput == Substring { + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { @_disfavoredOverload public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == Substring { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) where RegexOutput == Substring { + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { @_disfavoredOverload public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == Substring { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + ) where RegexOutput == Substring { + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Repeat { @_disfavoredOverload 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)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } @_disfavoredOverload 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)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } @_disfavoredOverload public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == Substring, R.Bound == Int { + _ behavior: RegexRepetitionBehavior? = nil + ) where RegexOutput == Substring, R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == Substring, R.Bound == Int { + ) where RegexOutput == Substring, R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?), Component.Output == (W, C0) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Optionally { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?), Component.Output == (W, C0) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?)> where Component.Output == (W, C0) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + ) -> Regex<(Substring, C1?)> where Component.RegexOutput == (W, C1) { + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { - public init( + public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?), Component.Output == (W, C0) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?), Component.Output == (W, C0) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( + public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0), Component.Output == (W, C0) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0), Component.Output == (W, C0) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Repeat { - public init( + public init( _ component: Component, count: Int - ) where Output == (Substring, C0?), Component.Output == (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(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?), Component.Output == (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(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - public init( + public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?), Component.Output == (W, C0), R.Bound == Int { + _ behavior: RegexRepetitionBehavior? = nil + ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( + public init( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?), Component.Output == (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: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Optionally { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?)> where Component.Output == (W, C0, C1) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + ) -> Regex<(Substring, C1?, C2?)> where Component.RegexOutput == (W, C1, C2) { + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { - public init( + public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( + public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1), Component.Output == (W, C0, C1) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1), Component.Output == (W, C0, C1) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Repeat { - public init( + public init( _ component: Component, count: Int - ) where Output == (Substring, C0?, C1?), Component.Output == (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(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?), Component.Output == (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(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - public init( + public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1), R.Bound == Int { + _ behavior: RegexRepetitionBehavior? = nil + ) 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: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?), Component.Output == (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: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Optionally { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Output == (W, C0, C1, C2) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + ) -> 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 { - public init( + public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( + public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1, C2), Component.Output == (W, C0, C1, C2) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2), Component.Output == (W, C0, C1, C2) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Repeat { - public init( + public init( _ component: Component, count: Int - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (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(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (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(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - public init( + public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2), R.Bound == Int { + _ behavior: RegexRepetitionBehavior? = nil + ) 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: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (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: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Optionally { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Output == (W, C0, C1, C2, C3) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + ) -> 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 { - public init( + public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( + public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1, C2, C3), Component.Output == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3), Component.Output == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Repeat { - public init( + public init( _ component: Component, count: Int - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (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(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - public init( + public init( count: Int, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (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(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - public init( + public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3), R.Bound == Int { + _ behavior: RegexRepetitionBehavior? = nil + ) 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: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (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: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Optionally { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Output == (W, C0, C1, C2, C3, C4) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + ) -> 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 { - public init( + public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( + public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0, C1, C2, C3, C4), Component.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4), Component.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Repeat { - public init( + 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, 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(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - public init( + 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, 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(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - public init( + public init( _ 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 { + _ behavior: RegexRepetitionBehavior? = nil + ) 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: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (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: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Optionally { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - public static func buildLimitedAvailability( + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + ) -> 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 { - public init( + 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) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( + 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) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5), Component.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Repeat { - public init( + 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, 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(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - public init( + 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, 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(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - public init( + public init( _ 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 { + _ behavior: RegexRepetitionBehavior? = nil + ) 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: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> 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, 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: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Optionally { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - public static func buildLimitedAvailability( + 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) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + ) -> 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 { - public init( + 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) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( + 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) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Repeat { - public init( + 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, 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(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - public init( + 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, 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(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - public init( + public init( _ 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 { + _ behavior: RegexRepetitionBehavior? = nil + ) 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: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @RegexComponentBuilder _ component: () -> 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, 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: QuantificationBehavior = .eagerly - ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Optionally { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @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) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - public static func buildLimitedAvailability( + 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) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + ) -> 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 { - public init( + 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) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @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) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( + 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) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @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) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Repeat { - public init( + 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, 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(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - public init( + 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, 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(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - public init( + public init( _ 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 { + _ behavior: RegexRepetitionBehavior? = nil + ) 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: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @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), 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: 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) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Optionally { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @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) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - public static func buildLimitedAvailability( + 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) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + ) -> 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 { - public init( + 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) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @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) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( + 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) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @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) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Repeat { - public init( + 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, 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(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - public init( + 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, 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(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - public init( + public init( _ 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 { + _ behavior: RegexRepetitionBehavior? = nil + ) 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: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @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), 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: 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) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Optionally { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @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) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - public static func buildLimitedAvailability( + 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) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + ) -> 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 { - public init( + 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) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension ZeroOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @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) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( + 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) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + _ behavior: RegexRepetitionBehavior? = nil + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension OneOrMore { - public init( - _ behavior: QuantificationBehavior = .eagerly, + public init( + _ behavior: RegexRepetitionBehavior? = nil, @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) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + ) 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)) } } +@available(SwiftStdlib 5.7, *) extension Repeat { - public init( + 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, 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(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(count), .default, component.regex.root)) } - public init( + 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, 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(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(count), .default, component().regex.root)) } - public init( + public init( _ 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 { + _ behavior: RegexRepetitionBehavior? = nil + ) 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: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @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), 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..( _ component: Component - ) where Output == Substring { + ) where RegexOutput == Substring { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { + @available(SwiftStdlib 5.7, *) @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == Substring { + ) where RegexOutput == Substring { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { - public init( + @available(SwiftStdlib 5.7, *) + public init( _ component: Component - ) where Output == (Substring, C0), Component.Output == (W, C0) { + ) where RegexOutput == (Substring, C1), Component.RegexOutput == (W, C1) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component.regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { - public init( + @available(SwiftStdlib 5.7, *) + public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0), Component.Output == (W, C0) { + ) where RegexOutput == (Substring, C1), Component.RegexOutput == (W, C1) { self.init(node: .nonCapturingGroup(.atomicNonCapturing, component().regex.root)) } } +@available(SwiftStdlib 5.7, *) extension Local { - public init( + @available(SwiftStdlib 5.7, *) + public init( _ component: Component - ) where Output == (Substring, C0, C1), Component.Output == (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 { - public init( + @available(SwiftStdlib 5.7, *) + public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1), Component.Output == (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 { - public init( + @available(SwiftStdlib 5.7, *) + public init( _ component: Component - ) where Output == (Substring, C0, C1, C2), Component.Output == (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 { - public init( + @available(SwiftStdlib 5.7, *) + public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2), Component.Output == (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 { - public init( + @available(SwiftStdlib 5.7, *) + public init( _ component: Component - ) where Output == (Substring, C0, C1, C2, C3), Component.Output == (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 { - public init( + @available(SwiftStdlib 5.7, *) + public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3), Component.Output == (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 { - public init( + @available(SwiftStdlib 5.7, *) + public init( _ component: Component - ) where Output == (Substring, C0, C1, C2, C3, C4), Component.Output == (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 { - public init( + @available(SwiftStdlib 5.7, *) + public init( @RegexComponentBuilder _ component: () -> Component - ) where Output == (Substring, C0, C1, C2, C3, C4), Component.Output == (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 { - public init( + @available(SwiftStdlib 5.7, *) + 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, 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 { - public init( + @available(SwiftStdlib 5.7, *) + 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, 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 { - public init( + @available(SwiftStdlib 5.7, *) + 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, 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 { - public init( + @available(SwiftStdlib 5.7, *) + 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, 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 { - public init( + @available(SwiftStdlib 5.7, *) + 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, 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 { - public init( + @available(SwiftStdlib 5.7, *) + 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, 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 { - public init( + @available(SwiftStdlib 5.7, *) + 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, 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 { - public init( + @available(SwiftStdlib 5.7, *) + 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, 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 { - public init( + @available(SwiftStdlib 5.7, *) + 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, 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 Local { - public init( + @available(SwiftStdlib 5.7, *) + 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, 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 { public static func buildPartialBlock( accumulated: R0, next: R1 @@ -1740,555 +2015,601 @@ extension AlternationBuilder { .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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)) } } +@available(SwiftStdlib 5.7, *) 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, C1?)> where R: RegexComponent, R.RegexOutput == (W, C1) { .init(node: .orderedChoice([regex.regex.root])) } } +@available(SwiftStdlib 5.7, *) 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, C1?, C2?)> where R: RegexComponent, R.RegexOutput == (W, C1, C2) { .init(node: .orderedChoice([regex.regex.root])) } } +@available(SwiftStdlib 5.7, *) 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, C1?, C2?, C3?)> where R: RegexComponent, R.RegexOutput == (W, C1, C2, C3) { .init(node: .orderedChoice([regex.regex.root])) } } +@available(SwiftStdlib 5.7, *) 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, 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 { - 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, 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 { - 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, 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 { - 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, 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 { - 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, 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 { - 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, 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 { - 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, 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])) } } // MARK: - Non-builder capture arity 0 +@available(SwiftStdlib 5.7, *) 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)) } - @_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, 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 +2622,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( @@ -2310,15 +2631,18 @@ extension TryCapture { }, component.regex.root))) } +} +@available(SwiftStdlib 5.7, *) +extension TryCapture { @_disfavoredOverload public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture), R.Output == W { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -2327,13 +2651,13 @@ extension TryCapture { public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture), R.Output == W { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == 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))) } @@ -2341,11 +2665,12 @@ extension TryCapture { // MARK: - Builder capture arity 0 +@available(SwiftStdlib 5.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)) } @@ -2353,46 +2678,17 @@ 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)) } - @_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, 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 @@ -2405,7 +2701,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( @@ -2414,15 +2710,18 @@ extension TryCapture { }, component().regex.root))) } +} +@available(SwiftStdlib 5.7, *) +extension TryCapture { @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture), R.Output == W { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -2431,13 +2730,13 @@ extension TryCapture { public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture), R.Output == W { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == 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))) } @@ -2445,50 +2744,24 @@ extension TryCapture { // MARK: - Non-builder capture arity 1 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + public init( _ component: R - ) where Output == (Substring, W, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, W, C1), R.RegexOutput == (W, C1) { self.init(node: .capture(component.regex.root)) } - public init( + public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, W, C1), R.RegexOutput == (W, C1) { 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( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0), R.Output == (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 @@ -2496,11 +2769,11 @@ extension TryCapture { component.regex.root))) } - public init( + public init( _ component: R, as reference: Reference, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture( reference: reference.id, .transform( @@ -2509,28 +2782,31 @@ extension TryCapture { }, component.regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } - public init( + public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, 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))) } @@ -2538,53 +2814,27 @@ extension TryCapture { // MARK: - Builder capture arity 1 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, W, C1), R.RegexOutput == (W, C1) { self.init(node: .capture(component().regex.root)) } - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, W, C1), R.RegexOutput == (W, C1) { self.init(node: .capture( reference: reference.id, 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( + public init( @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0), R.Output == (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 @@ -2592,11 +2842,11 @@ extension TryCapture { component().regex.root))) } - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture( reference: reference.id, .transform( @@ -2605,28 +2855,31 @@ extension TryCapture { }, component().regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, 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))) } @@ -2634,50 +2887,24 @@ extension TryCapture { // MARK: - Non-builder capture arity 2 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + public init( _ component: R - ) where Output == (Substring, W, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, W, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture(component.regex.root)) } - public init( + public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, W, C1, C2), R.RegexOutput == (W, C1, C2) { 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( + public init( _ component: R, transform: @escaping (Substring) throws -> NewCapture - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (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 @@ -2685,11 +2912,11 @@ extension TryCapture { component.regex.root))) } - public init( + public init( _ 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, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture( reference: reference.id, .transform( @@ -2698,28 +2925,31 @@ extension TryCapture { }, component.regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } - public init( + public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, 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))) } @@ -2727,53 +2957,27 @@ extension TryCapture { // MARK: - Builder capture arity 2 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, W, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture(component().regex.root)) } - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1), R.Output == (W, C0, C1) { + ) where RegexOutput == (Substring, W, C1, C2), R.RegexOutput == (W, C1, C2) { 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), 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( + 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, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2781,11 +2985,11 @@ extension TryCapture { component().regex.root))) } - public init( + public init( 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, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture( reference: reference.id, .transform( @@ -2794,28 +2998,31 @@ extension TryCapture { }, component().regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } - public init( + public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, 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))) } @@ -2823,50 +3030,24 @@ extension TryCapture { // MARK: - Non-builder capture arity 3 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + public init( _ component: R - ) where Output == (Substring, W, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, W, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(component.regex.root)) } - public init( + public init( _ component: R, as reference: Reference - ) where Output == (Substring, W, C0, C1, C2), R.Output == (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)) } - 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( + 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, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2874,11 +3055,11 @@ extension TryCapture { component.regex.root))) } - public init( + public init( _ 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, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture( reference: reference.id, .transform( @@ -2887,28 +3068,31 @@ extension TryCapture { }, component.regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } - public init( + public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, 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))) } @@ -2916,53 +3100,27 @@ extension TryCapture { // MARK: - Builder capture arity 3 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2), R.Output == (W, C0, C1, C2) { + ) where RegexOutput == (Substring, W, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(component().regex.root)) } - public init( + 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, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { 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), 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( + 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, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { try transform($0) as Any @@ -2970,11 +3128,11 @@ extension TryCapture { component().regex.root))) } - public init( + public init( 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, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture( reference: reference.id, .transform( @@ -2983,28 +3141,31 @@ extension TryCapture { }, component().regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture(.transform( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, 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))) } @@ -3012,50 +3173,24 @@ extension TryCapture { // MARK: - Non-builder capture arity 4 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + public init( _ component: R - ) where Output == (Substring, W, C0, C1, C2, C3), R.Output == (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)) } - public init( + 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, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { 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( + 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, 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 @@ -3063,11 +3198,11 @@ extension TryCapture { component.regex.root))) } - public init( + public init( _ 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, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, .transform( @@ -3076,28 +3211,31 @@ extension TryCapture { }, component.regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + public init( _ component: R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, 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))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, 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))) } @@ -3105,53 +3243,27 @@ extension TryCapture { // MARK: - Builder capture arity 4 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + public init( @RegexComponentBuilder _ component: () -> R - ) where Output == (Substring, W, C0, C1, C2, C3), R.Output == (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)) } - public init( + 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, C1, C2, C3, C4), R.RegexOutput == (W, 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), 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( + 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, 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 @@ -3159,11 +3271,11 @@ extension TryCapture { component().regex.root))) } - public init( + public init( 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, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, .transform( @@ -3172,28 +3284,31 @@ extension TryCapture { }, component().regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? - ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, 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))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, 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))) } @@ -3201,50 +3316,24 @@ extension TryCapture { // MARK: - Non-builder capture arity 5 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + 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, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture(component.regex.root)) } - public init( + 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, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { 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( + 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, 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 @@ -3252,11 +3341,11 @@ extension TryCapture { component.regex.root))) } - public init( + public init( _ 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, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, .transform( @@ -3265,28 +3354,31 @@ extension TryCapture { }, component.regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3294,53 +3386,27 @@ extension TryCapture { // MARK: - Builder capture arity 5 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + 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, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture(component().regex.root)) } - public init( + 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, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { 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))) - } -} - -extension TryCapture { - public init( + 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, 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 @@ -3348,11 +3414,11 @@ extension TryCapture { component().regex.root))) } - public init( + public init( 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, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, .transform( @@ -3361,28 +3427,31 @@ extension TryCapture { }, component().regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3390,50 +3459,24 @@ extension TryCapture { // MARK: - Non-builder capture arity 6 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + 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, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(component.regex.root)) } - public init( + 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, 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)) } - 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( + 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, 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 @@ -3441,11 +3484,11 @@ extension TryCapture { component.regex.root))) } - public init( + public init( _ 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, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, .transform( @@ -3454,28 +3497,31 @@ extension TryCapture { }, component.regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3483,53 +3529,27 @@ extension TryCapture { // MARK: - Builder capture arity 6 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + 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, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture(component().regex.root)) } - public init( + 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, 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)) } - 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( + 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, 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 @@ -3537,11 +3557,11 @@ extension TryCapture { component().regex.root))) } - public init( + public init( 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, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, .transform( @@ -3550,28 +3570,31 @@ extension TryCapture { }, component().regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3579,50 +3602,24 @@ extension TryCapture { // MARK: - Non-builder capture arity 7 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + 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, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(component.regex.root)) } - public init( + 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, 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)) } - 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( + 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, 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 @@ -3630,11 +3627,11 @@ extension TryCapture { component.regex.root))) } - public init( + public init( _ 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, 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( @@ -3643,28 +3640,31 @@ extension TryCapture { }, component.regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3672,53 +3672,27 @@ extension TryCapture { // MARK: - Builder capture arity 7 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + 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, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture(component().regex.root)) } - public init( + 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, 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)) } - 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( + 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, 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 @@ -3726,11 +3700,11 @@ extension TryCapture { component().regex.root))) } - public init( + public init( 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, 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( @@ -3739,28 +3713,31 @@ extension TryCapture { }, component().regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3768,50 +3745,24 @@ extension TryCapture { // MARK: - Non-builder capture arity 8 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + 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, 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)) } - public init( + 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, 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)) } - 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( + 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, 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 @@ -3819,11 +3770,11 @@ extension TryCapture { component.regex.root))) } - public init( + public init( _ 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, 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( @@ -3832,28 +3783,31 @@ extension TryCapture { }, component.regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -3861,53 +3815,27 @@ extension TryCapture { // MARK: - Builder capture arity 8 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + 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, 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)) } - public init( + 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, 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)) } - 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( + 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, 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 @@ -3915,11 +3843,11 @@ extension TryCapture { component().regex.root))) } - public init( + public init( 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, 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( @@ -3928,28 +3856,31 @@ extension TryCapture { }, component().regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -3957,50 +3888,24 @@ extension TryCapture { // MARK: - Non-builder capture arity 9 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + 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, 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)) } - public init( + 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, 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)) } - 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( + 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, 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 @@ -4008,11 +3913,11 @@ extension TryCapture { component.regex.root))) } - public init( + public init( _ 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, 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( @@ -4021,28 +3926,31 @@ extension TryCapture { }, component.regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -4050,53 +3958,27 @@ extension TryCapture { // MARK: - Builder capture arity 9 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + 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, 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)) } - public init( + 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, 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)) } - 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( + 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, 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 @@ -4104,11 +3986,11 @@ extension TryCapture { component().regex.root))) } - public init( + public init( 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, 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( @@ -4117,28 +3999,31 @@ extension TryCapture { }, component().regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } @@ -4146,50 +4031,24 @@ extension TryCapture { // MARK: - Non-builder capture arity 10 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + 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, 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)) } - public init( + 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, 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)) } - 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( + 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, 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 @@ -4197,11 +4056,11 @@ extension TryCapture { component.regex.root))) } - public init( + public init( _ 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, 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( @@ -4210,28 +4069,31 @@ extension TryCapture { }, component.regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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( CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? + try transform($0) as Any? }, component.regex.root))) } @@ -4239,53 +4101,27 @@ extension TryCapture { // MARK: - Builder capture arity 10 +@available(SwiftStdlib 5.7, *) extension Capture { - public init( + 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, 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)) } - public init( + 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, 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)) } - 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( + 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, 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 @@ -4293,11 +4129,11 @@ extension TryCapture { component().regex.root))) } - public init( + public init( 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, 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( @@ -4306,28 +4142,31 @@ extension TryCapture { }, component().regex.root))) } +} - public init( +@available(SwiftStdlib 5.7, *) +extension TryCapture { + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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) { - transform($0) as Any? + try transform($0) as Any? }, component().regex.root))) } - public init( + 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) { + transform: @escaping (Substring) throws -> NewCapture? + ) 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( 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..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.. 1) precondition(maxArity < Counter.bitWidth) @@ -120,20 +141,17 @@ struct VariadicsGenerator: ParsableCommand { // BEGIN AUTO-GENERATED CONTENT - import _RegexParser @_spi(RegexBuilder) import _StringProcessing """) - 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 +161,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 +202,7 @@ struct VariadicsGenerator: ParsableCommand { output("// END AUTO-GENERATED CONTENT\n") - print("Done!", to: &standardError) + log("Done!") } func tupleType(arity: Int, genericParameters: () -> String) -> String { @@ -199,10 +215,8 @@ struct VariadicsGenerator: ParsableCommand { func emitConcatenation(leftArity: Int, rightArity: Int) { let genericParams: String = { - var result = "W0, W1" - result += (0..( accumulated: R0, next: R1 ) -> \(regexTypeName)<\(matchType)> \(whereClause) { @@ -255,9 +270,11 @@ struct VariadicsGenerator: ParsableCommand { func emitConcatenationWithEmpty(leftArity: Int) { // T + () = T output(""" - extension \(concatBuilderName) { - public static func buildPartialBlock 0 { - result += "W" - result += (0..= 0) let params = QuantifierParameters(kind: kind, arity: arity) output(""" + \(defaultAvailableAttr) extension \(kind.rawValue) { - \(params.disfavored)\ + \(params.disfavored)\ public init<\(params.genericParams)>( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: RegexRepetitionBehavior? = nil ) \(params.whereClauseForInit) { - self.init(node: .quantification(.\(kind.astQuantifierAmount), behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.dslTreeKind) } ?? .default + self.init(node: .quantification(.\(kind.astQuantifierAmount), kind, component.regex.root)) } } + \(defaultAvailableAttr) extension \(kind.rawValue) { - \(params.disfavored)\ + \(params.disfavored)\ public init<\(params.genericParams)>( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = 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.dslTreeKind) } ?? .default + self.init(node: .quantification(.\(kind.astQuantifierAmount), kind, component().regex.root)) } } \(kind == .zeroOrOne ? """ + \(defaultAvailableAttr) extension \(concatBuilderName) { 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)) } } """ : "") @@ -413,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) { @@ -442,8 +464,10 @@ struct VariadicsGenerator: ParsableCommand { } } + \(defaultAvailableAttr) extension \(groupName) { - \(disfavored)\ + \(defaultAvailableAttr) + \(disfavored)\ public init<\(genericParams)>( @\(concatBuilderName) _ component: () -> Component ) \(whereClauseForInit) { @@ -463,40 +487,41 @@ struct VariadicsGenerator: ParsableCommand { // We would need to prohibit `repeat(count: 0)`; can only happen at runtime output(""" + \(defaultAvailableAttr) extension Repeat { - \(params.disfavored)\ + \(params.disfavored)\ public init<\(params.genericParams)>( _ component: Component, count: Int ) \(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(count), .default, component.regex.root)) } - \(params.disfavored)\ + \(params.disfavored)\ public init<\(params.genericParams)>( count: Int, @\(concatBuilderName) _ component: () -> Component ) \(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(count), .default, component().regex.root)) } - \(params.disfavored)\ + \(params.disfavored)\ public init<\(params.genericParams), R: RangeExpression>( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: RegexRepetitionBehavior? = nil ) \(params.repeatingWhereClause) { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: RegexRepetitionBehavior? = nil, @\(concatBuilderName) _ component: () -> Component ) \(params.repeatingWhereClause) { self.init(node: .repeating(expression.relative(to: 0..( accumulated: R0, next: R1 @@ -558,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])) @@ -581,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)) } - \(disfavored)\ + \(disfavored)\ public init<\(genericParams)>( _ component: R, as reference: Reference ) \(whereClauseRaw) { 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)\ + \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, transform: @escaping (Substring) throws -> NewCapture @@ -656,7 +655,7 @@ struct VariadicsGenerator: ParsableCommand { component.regex.root))) } - \(disfavored)\ + \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, as reference: Reference, @@ -670,30 +669,33 @@ struct VariadicsGenerator: ParsableCommand { }, component.regex.root))) } + } - \(disfavored)\ + \(defaultAvailableAttr) + 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))) } - \(disfavored)\ + \(disfavored)\ 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))) } @@ -701,15 +703,16 @@ struct VariadicsGenerator: ParsableCommand { // MARK: - Builder capture arity \(arity) + \(defaultAvailableAttr) extension Capture { - \(disfavored)\ + \(disfavored)\ public init<\(genericParams)>( @\(concatBuilderName) _ component: () -> R ) \(whereClauseRaw) { self.init(node: .capture(component().regex.root)) } - \(disfavored)\ + \(disfavored)\ public init<\(genericParams)>( as reference: Reference, @\(concatBuilderName) _ component: () -> R @@ -719,36 +722,7 @@ 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)\ + \(disfavored)\ public init<\(genericParams), NewCapture>( @\(concatBuilderName) _ component: () -> R, transform: @escaping (Substring) throws -> NewCapture @@ -760,7 +734,7 @@ struct VariadicsGenerator: ParsableCommand { component().regex.root))) } - \(disfavored)\ + \(disfavored)\ public init<\(genericParams), NewCapture>( as reference: Reference, @\(concatBuilderName) _ component: () -> R, @@ -774,30 +748,33 @@ struct VariadicsGenerator: ParsableCommand { }, component().regex.root))) } + } - \(disfavored)\ + \(defaultAvailableAttr) + 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))) } - \(disfavored)\ + \(disfavored)\ 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/_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 3ce6e3591..f846ddf68 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/_RegexParser/Regex/AST/AST.swift b/Sources/_RegexParser/Regex/AST/AST.swift index ba37b6d62..a7dcd2015 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,14 +23,8 @@ 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. - public var captureStructure: CaptureStructure { - var constructor = CaptureStructure.Constructor(.flatten) - return root._captureStructure(&constructor) - } } extension AST { @@ -94,7 +89,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 +100,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 +108,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 +119,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 +200,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 { @@ -304,78 +303,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/_RegexParser/Regex/AST/Atom.swift b/Sources/_RegexParser/Regex/AST/Atom.swift index 0aa0951c5..e17ce68bb 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 @@ -397,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? @@ -414,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 @@ -573,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 @@ -631,9 +632,46 @@ 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. + /// 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): @@ -642,34 +680,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. @@ -683,7 +694,7 @@ extension AST.Atom { return nil case .property, .any, .startOfLine, .endOfLine, .backreference, .subpattern, - .callout, .backtrackingDirective: + .callout, .backtrackingDirective, .changeMatchingOptions: return nil } } @@ -702,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 { @@ -723,7 +734,7 @@ extension AST.Atom { case .property, .escaped, .any, .startOfLine, .endOfLine, .backreference, .subpattern, .namedCharacter, .callout, - .backtrackingDirective: + .backtrackingDirective, .changeMatchingOptions: return nil } } @@ -732,6 +743,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/CustomCharClass.swift b/Sources/_RegexParser/Regex/AST/CustomCharClass.swift index 614048f0a..c1dd4c620 100644 --- a/Sources/_RegexParser/Regex/AST/CustomCharClass.swift +++ b/Sources/_RegexParser/Regex/AST/CustomCharClass.swift @@ -97,14 +97,19 @@ extension CustomCC.Member { if case .trivia = self { return true } return false } + + public var isSemantic: Bool { + !isTrivia + } } 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 { !$0.isTrivia } + copy.members = copy.members.filter(\.isSemantic) return copy } } diff --git a/Sources/_RegexParser/Regex/AST/Group.swift b/Sources/_RegexParser/Regex/AST/Group.swift index 81e0931ad..8ecaadeda 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 @@ -80,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 @@ -87,22 +86,9 @@ 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: + /// The name of the 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. + /// 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 @@ -113,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 808b51287..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 @@ -41,7 +41,11 @@ extension AST { case graphemeClusterSemantics // X case unicodeScalarSemantics // u case byteSemantics // b + + // Swift-only default possessive quantifier + case possessiveByDefault // t.b.d. } + public var kind: Kind public var location: SourceLocation @@ -79,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 @@ -134,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/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 8298dc207..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,16 +57,17 @@ 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 } - /// 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 @@ -301,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 >= @@ -360,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] } @@ -414,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 ?? "" @@ -444,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/Parse/CharacterPropertyClassification.swift b/Sources/_RegexParser/Regex/Parse/CharacterPropertyClassification.swift index e5b65a46c..5cc920063 100644 --- a/Sources/_RegexParser/Regex/Parse/CharacterPropertyClassification.swift +++ b/Sources/_RegexParser/Regex/Parse/CharacterPropertyClassification.swift @@ -32,8 +32,8 @@ extension Source { static private func classifyGeneralCategory( _ str: String ) -> Unicode.ExtendedGeneralCategory? { - // This uses the aliases defined in - // https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt. + // This uses the aliases defined in https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt. + // Additionally, uses the `L& = Lc` alias defined by PCRE. withNormalizedForms(str) { str in switch str { case "c", "other": return .other @@ -43,7 +43,7 @@ extension Source { case "co", "privateuse": return .privateUse case "cs", "surrogate": return .surrogate case "l", "letter": return .letter - case "lc", "casedletter": return .casedLetter + case "lc", "l&", "casedletter": return .casedLetter case "ll", "lowercaseletter": return .lowercaseLetter case "lm", "modifierletter": return .modifierLetter case "lo", "otherletter": return .otherLetter @@ -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/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/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/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/_RegexParser/Regex/Parse/LexicalAnalysis.swift b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift index c48d53de9..9633b607e 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.. 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 @@ -846,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("?") { @@ -871,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 { @@ -1035,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) } } @@ -1066,9 +1069,13 @@ extension Source { mutating func lexCustomCCStart( ) 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() else { + return nil + } if src.tryEat("[") { return src.tryEat("^") ? .inverted : .normal } @@ -1101,10 +1108,33 @@ extension Source { private mutating func lexPOSIXCharacterProperty( ) 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) + 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() -> Bool { + do { + var src = self + 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 + // try and lex it. + return true } } @@ -1129,26 +1159,60 @@ 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 + 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 + // 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 +1228,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) } } @@ -1177,17 +1244,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 { @@ -1416,8 +1485,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 } @@ -1431,6 +1513,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. @@ -1691,13 +1776,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) @@ -1758,18 +1850,16 @@ 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. Like \p{...} this is also allowed outside of + // a custom character class. + if let prop = try src.lexPOSIXCharacterProperty()?.value { return .property(prop) } // 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. @@ -1787,6 +1877,9 @@ extension Source { } throw Unreachable("TODO: reason") + case "(" where !customCC: + throw Unreachable("Should have lexed a group or group-like atom") + // (sometimes) special metacharacters case ".": return customCC ? .char(".") : .any case "^": return customCC ? .char("^") : .startOfLine diff --git a/Sources/_RegexParser/Regex/Parse/Mocking.swift b/Sources/_RegexParser/Regex/Parse/Mocking.swift deleted file mode 100644 index dd02e0fc7..000000000 --- a/Sources/_RegexParser/Regex/Parse/Mocking.swift +++ /dev/null @@ -1,125 +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 -// -//===----------------------------------------------------------------------===// - -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. -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)`. -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/Sources/_RegexParser/Regex/Parse/Parse.swift b/Sources/_RegexParser/Regex/Parse/Parse.swift index c3aa3500b..ec6e1c26c 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) } @@ -438,16 +454,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 +476,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 +491,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 +504,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() { @@ -556,11 +577,21 @@ 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 { 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 { + /// An error that includes information about the location in source code. + public struct LocatedError: Error, LocatedErrorProtocol { public let error: E public let location: SourceLocation @@ -70,13 +75,12 @@ extension Source { self.error = v self.location = Location(r) } - } - /// 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 @@ -117,4 +121,8 @@ extension Source.LocatedError: CustomStringConvertible { // we present the message to the compiler. "\(error)" } + + public var _typeErasedError: Error { + return error + } } 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 0e40ad2ce..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 @@ -156,6 +157,9 @@ extension AST.Atom { case .backtrackingDirective(let d): return "\(d)" + case .changeMatchingOptions(let opts): + return "changeMatchingOptions<\(opts)>" + case .char, .scalar: fatalError("Unreachable") } @@ -225,22 +229,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)>" } } } @@ -312,7 +315,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/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift b/Sources/_RegexParser/Regex/Printing/PrettyPrinter.swift index f1d8c83b0..8ddcd73c7 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 @@ -32,6 +40,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 @@ -46,25 +57,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 + /// This is the low-level interface to the pretty printer. /// - /// 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 +85,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 +100,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 +121,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 +130,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/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 55d3d3adc..d37dfbd4a 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 { @@ -161,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) { @@ -176,3 +182,5 @@ public struct AnyType: Equatable, Hashable { hasher.combine(ObjectIdentifier(base)) } } + + 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/Contains.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift index dbe7923ec..2a1ef72a2 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,17 +22,40 @@ extension Collection { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { - public func contains(_ other: S) -> Bool - where S.Element == Element + /// 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`. + @available(SwiftStdlib 5.7, *) + public func contains(_ other: C) -> Bool + where C.Element == Element { firstRange(of: other) != nil } } extension BidirectionalCollection where Element: Comparable { - public 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 + } + fatalError() + } +} + +// 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 } } @@ -40,6 +63,12 @@ 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`. + @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 40d5b9950..42703827e 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 { + /// 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 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 { + /// 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 other: C + ) -> Range? where C.Element == Element { let searcher = PatternOrEmpty( searcher: TwoWaySearcher(pattern: Array(other))) let slice = self[...] @@ -56,11 +70,18 @@ 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. + @available(SwiftStdlib 5.7, *) public func firstRange(of regex: R) -> Range? { firstRange(of: RegexConsumer(regex)) } - - public func lastRange(of regex: R) -> Range? { + + @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 e56e35e72..33a9748ac 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,11 +175,24 @@ extension BidirectionalCollection { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { - public 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: ==)) } + + // 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: C + ) -> [Range] where C.Element == Element { + ranges(of: ZSearcher(pattern: Array(other), by: ==)).map { $0 } + } } extension BidirectionalCollection where Element: Equatable { @@ -194,10 +207,10 @@ extension BidirectionalCollection where Element: Equatable { } extension BidirectionalCollection where Element: Comparable { - public 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)))) } @@ -216,15 +229,32 @@ extension BidirectionalCollection where Element: Comparable { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func ranges( + @available(SwiftStdlib 5.7, *) + @_disfavoredOverload + func ranges( of regex: R ) -> RangesCollection> { ranges(of: RegexConsumer(regex)) } - - public func rangesFromBack( + + @available(SwiftStdlib 5.7, *) + func rangesFromBack( of regex: R ) -> 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/Replace.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift index e2c9d78a4..217fb90d6 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,36 +67,64 @@ extension RangeReplaceableCollection { // MARK: Fixed pattern algorithms extension RangeReplaceableCollection where Element: Equatable { - public func replacing( - _ other: S, + /// 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`. + @available(SwiftStdlib 5.7, *) + 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, subrange: subrange, maxReplacements: maxReplacements) } - - public func replacing( - _ other: S, + + /// 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`. + @available(SwiftStdlib 5.7, *) + 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, subrange: startIndex..( - _ other: S, + + /// 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`. + @available(SwiftStdlib 5.7, *) + 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, @@ -108,12 +136,12 @@ extension RangeReplaceableCollection where Element: Equatable { extension RangeReplaceableCollection where Self: BidirectionalCollection, Element: Comparable { - public 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, @@ -121,11 +149,11 @@ extension RangeReplaceableCollection maxReplacements: maxReplacements) } - public 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, @@ -133,11 +161,11 @@ extension RangeReplaceableCollection maxReplacements: maxReplacements) } - public 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, @@ -149,6 +177,17 @@ 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`. + @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, with replacement: Replacement, @@ -161,7 +200,17 @@ 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`. + @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, with replacement: Replacement, @@ -173,7 +222,15 @@ 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..ab465c382 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -11,17 +11,32 @@ // MARK: `SplitCollection` -public struct SplitCollection { +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,101 +45,135 @@ 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 index == base.endIndex { + return finish() } - defer { index = range.upperBound } - return base[index..= maxSplits { + return finish() + } + + while true { + // If there are no more ranges that matched, return the rest of `base`. + guard let range = ranges.next() else { + return finish() + } + + defer { index = range.upperBound } + + if omittingEmptySubsequences && index == range.lowerBound { + continue + } + + splitCounter += 1 + 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 - } - } - - public 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` -public struct ReversedSplitCollection { +struct ReversedSplitCollection { public typealias Base = Searcher.BackwardSearched let ranges: ReversedRangesCollection @@ -175,16 +224,21 @@ extension ReversedSplitCollection: Sequence { // MARK: `CollectionSearcher` algorithms extension Collection { - public func split( - by separator: Searcher + func split( + 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) } } extension BidirectionalCollection { - public func splitFromBack( + func splitFromBack( by separator: Searcher ) -> ReversedSplitCollection where Searcher.BackwardSearched == Self @@ -197,15 +251,17 @@ extension BidirectionalCollection { extension Collection { // TODO: Non-escaping and throwing - public func split( - whereSeparator predicate: @escaping (Element) -> Bool + func split( + whereSeparator predicate: @escaping (Element) -> Bool, + maxSplits: Int, + omittingEmptySubsequences: Bool ) -> SplitCollection> { - split(by: PredicateConsumer(predicate: predicate)) + split(by: PredicateConsumer(predicate: predicate), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) } } extension BidirectionalCollection where Element: Equatable { - public func splitFromBack( + func splitFromBack( whereSeparator predicate: @escaping (Element) -> Bool ) -> ReversedSplitCollection> { splitFromBack(by: PredicateConsumer(predicate: predicate)) @@ -215,15 +271,17 @@ extension BidirectionalCollection where Element: Equatable { // MARK: Single element algorithms extension Collection where Element: Equatable { - public func split( - by separator: Element + func split( + by separator: Element, + maxSplits: Int, + omittingEmptySubsequences: Bool ) -> SplitCollection> { - split(whereSeparator: { $0 == separator }) + split(whereSeparator: { $0 == separator }, maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) } } extension BidirectionalCollection where Element: Equatable { - public func splitFromBack( + func splitFromBack( by separator: Element ) -> ReversedSplitCollection> { splitFromBack(whereSeparator: { $0 == separator }) @@ -233,10 +291,29 @@ extension BidirectionalCollection where Element: Equatable { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { - public func split( - by separator: S - ) -> SplitCollection> where S.Element == Element { - split(by: ZSearcher(pattern: Array(separator), by: ==)) + @_disfavoredOverload + 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 + /// 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. + @available(SwiftStdlib 5.7, *) + 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)) } } @@ -252,13 +329,16 @@ extension BidirectionalCollection where Element: Equatable { } extension BidirectionalCollection where Element: Comparable { - public func split( - by separator: S + func split( + by separator: C, + maxSplits: Int, + omittingEmptySubsequences: Bool ) -> SplitCollection>> - where S.Element == Element + where C.Element == Element { split( - by: PatternOrEmpty(searcher: TwoWaySearcher(pattern: Array(separator)))) + by: PatternOrEmpty(searcher: TwoWaySearcher(pattern: Array(separator))), + maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) } // FIXME @@ -274,16 +354,40 @@ extension BidirectionalCollection where Element: Comparable { // MARK: Regex algorithms +@available(SwiftStdlib 5.7, *) extension BidirectionalCollection where SubSequence == Substring { - public func split( - by separator: R + @_disfavoredOverload + func split( + by separator: R, + maxSplits: Int, + omittingEmptySubsequences: Bool ) -> SplitCollection> { - split(by: RegexConsumer(separator)) + split(by: RegexConsumer(separator), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) } - public func splitFromBack( + func splitFromBack( by separator: R ) -> ReversedSplitCollection> { splitFromBack(by: RegexConsumer(separator)) } + + // 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( + separator: R, + maxSplits: Int = .max, + omittingEmptySubsequences: Bool = true + ) -> [SubSequence] { + Array(split(by: RegexConsumer(separator), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences)) + } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift index 75c6e1133..2f45a734b 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)) @@ -47,12 +47,19 @@ 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`. 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..7411236da 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 { @@ -102,40 +102,48 @@ extension RangeReplaceableCollection where Self: BidirectionalCollection { // MARK: Predicate algorithms extension Collection { - // TODO: Non-escaping and throwing + 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: @escaping (Element) -> Bool - ) -> SubSequence { - trimmingPrefix(ManyConsumer(base: PredicateConsumer(predicate: predicate))) + 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...] } } 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.. 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 +151,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 +168,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,7 +186,15 @@ extension RangeReplaceableCollection where Self: BidirectionalCollection { // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { - public func trimmingPrefix( + /// 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`. + @available(SwiftStdlib 5.7, *) + public func trimmingPrefix( _ prefix: Prefix ) -> SubSequence where Prefix.Element == Element { trimmingPrefix(FixedPatternConsumer(pattern: prefix)) @@ -186,7 +202,13 @@ extension Collection where Element: Equatable { } extension Collection where SubSequence == Self, Element: Equatable { - public mutating func trimPrefix( + /// 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. + @available(SwiftStdlib 5.7, *) + public mutating func trimPrefix( _ prefix: Prefix ) where Prefix.Element == Element { trimPrefix(FixedPatternConsumer(pattern: prefix)) @@ -195,7 +217,13 @@ extension Collection where SubSequence == Self, Element: Equatable { extension RangeReplaceableCollection where Element: Equatable { @_disfavoredOverload - public mutating func trimPrefix( + /// 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. + @available(SwiftStdlib 5.7, *) + public mutating func trimPrefix( _ prefix: Prefix ) where Prefix.Element == Element { trimPrefix(FixedPatternConsumer(pattern: prefix)) @@ -203,13 +231,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 +247,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 +266,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 +285,23 @@ 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. + @available(SwiftStdlib 5.7, *) public func trimmingPrefix(_ regex: R) -> SubSequence { trimmingPrefix(RegexConsumer(regex)) } - - public func trimmingSuffix(_ regex: R) -> SubSequence { + + @available(SwiftStdlib 5.7, *) + func trimmingSuffix(_ regex: R) -> SubSequence { trimmingSuffix(RegexConsumer(regex)) } - - public func trimming(_ regex: R) -> SubSequence { + + @available(SwiftStdlib 5.7, *) + func trimming(_ regex: R) -> SubSequence { trimming(RegexConsumer(regex)) } } @@ -273,15 +309,20 @@ 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. + @available(SwiftStdlib 5.7, *) public mutating func trimPrefix(_ regex: R) { trimPrefix(RegexConsumer(regex)) } - - public mutating func trimSuffix(_ regex: R) { + + @available(SwiftStdlib 5.7, *) + mutating func trimSuffix(_ regex: R) { trimSuffix(RegexConsumer(regex)) } - - public mutating func trim(_ regex: R) { + + @available(SwiftStdlib 5.7, *) + mutating func trim(_ regex: R) { let consumer = RegexConsumer(regex) trimPrefix(consumer) trimSuffix(consumer) @@ -289,15 +330,18 @@ extension RangeReplaceableCollection } extension Substring { - public mutating func trimPrefix(_ regex: R) { + @available(SwiftStdlib 5.7, *) + mutating func trimPrefix(_ regex: R) { trimPrefix(RegexConsumer(regex)) } - - public mutating func trimSuffix(_ regex: R) { + + @available(SwiftStdlib 5.7, *) + mutating func trimSuffix(_ regex: R) { trimSuffix(RegexConsumer(regex)) } - - public mutating func trim(_ regex: R) { + + @available(SwiftStdlib 5.7, *) + 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/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 } } 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..4956406da 100644 --- a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift +++ b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift @@ -9,22 +9,25 @@ // //===----------------------------------------------------------------------===// -public struct RegexConsumer< +// 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 { // TODO: Should `Regex` itself implement these protocols? let regex: R - public init(_ regex: R) { + init(_ regex: R) { self.regex = regex } } +@available(SwiftStdlib 5.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 } @@ -35,10 +38,11 @@ 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 { - public typealias Match = R.Output + typealias Match = R.RegexOutput - public func matchingConsuming( + func matchingConsuming( _ consumed: Consumed, in range: Range ) -> (upperBound: String.Index, match: Match)? { _matchingConsuming(consumed[...], in: range) @@ -46,8 +50,9 @@ extension RegexConsumer: MatchingCollectionConsumer { } // TODO: We'll want to bake backwards into the engine +@available(SwiftStdlib 5.7, *) extension RegexConsumer: BidirectionalMatchingCollectionConsumer { - public func matchingConsumingBack( + func matchingConsumingBack( _ consumed: Consumed, in range: Range ) -> (lowerBound: String.Index, match: Match)? { var i = range.lowerBound @@ -66,13 +71,14 @@ extension RegexConsumer: BidirectionalMatchingCollectionConsumer { } } +@available(SwiftStdlib 5.7, *) 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) @@ -80,10 +86,11 @@ extension RegexConsumer: MatchingStatelessCollectionSearcher { } // TODO: Bake in search-back to engine too +@available(SwiftStdlib 5.7, *) 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/Matching/FirstMatch.swift b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift index c0699b805..4342391af 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,30 @@ extension BidirectionalCollection { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func firstMatch( + @available(SwiftStdlib 5.7, *) + @_disfavoredOverload + func firstMatch( of regex: R ) -> _MatchResult>? { firstMatch(of: RegexConsumer(regex)) } - - public func lastMatch( + + @available(SwiftStdlib 5.7, *) + 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. + @available(SwiftStdlib 5.7, *) + public func firstMatch( + of r: R + ) -> Regex.Match? { + let slice = self[...] + return try? r.regex.firstMatch(in: slice) + } } diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift index f99e525b5..206d68554 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,8 @@ extension RangeReplaceableCollection { // MARK: Regex algorithms extension RangeReplaceableCollection where SubSequence == Substring { - public func replacing( + @available(SwiftStdlib 5.7, *) + func replacing( _ regex: R, with replacement: (_MatchResult>) throws -> Replacement, subrange: Range, @@ -87,8 +88,9 @@ extension RangeReplaceableCollection where SubSequence == Substring { subrange: subrange, maxReplacements: maxReplacements) } - - public func replacing( + + @available(SwiftStdlib 5.7, *) + func replacing( _ regex: R, with replacement: (_MatchResult>) throws -> Replacement, maxReplacements: Int = .max @@ -99,8 +101,9 @@ extension RangeReplaceableCollection where SubSequence == Substring { subrange: startIndex..( + + @available(SwiftStdlib 5.7, *) + mutating func replace( _ regex: R, with replacement: (_MatchResult>) throws -> Replacement, maxReplacements: Int = .max @@ -110,4 +113,85 @@ 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. + /// - 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, + subrange: Range, + maxReplacements: Int = .max, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows -> Self where Replacement.Element == Element { + + precondition(maxReplacements >= 0) + + var index = subrange.lowerBound + var result = Self() + result.append(contentsOf: self[..( + _ regex: R, + maxReplacements: Int = .max, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows -> Self where Replacement.Element == Element { + try replacing( + regex, + subrange: startIndex..( + _ regex: R, + maxReplacements: Int = .max, + with replacement: (Regex.Match) throws -> Replacement + ) rethrows where Replacement.Element == Element { + self = try replacing( + regex, + 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,45 @@ extension BidirectionalCollection { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func matches( + @available(SwiftStdlib 5.7, *) + @_disfavoredOverload + func matches( of regex: R ) -> MatchesCollection> { matches(of: RegexConsumer(regex)) } - - public func matchesFromBack( + + @available(SwiftStdlib 5.7, *) + func matchesFromBack( of regex: R ) -> ReversedMatchesCollection> { matchesFromBack(of: RegexConsumer(regex)) } + + // 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, *) + public 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.. ) -> 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/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift b/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift index 11184f856..ae613cfd7 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,19 +36,21 @@ 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 { + // 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, @@ -57,7 +59,7 @@ extension TwoWaySearcher: CollectionSearcher { memory: nil) } - public func search( + func search( _ searched: Searched, _ state: inout State ) -> Range? { @@ -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.. { +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/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index d03a1e382..21fcfa703 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -1,4 +1,4 @@ -import _RegexParser +@_implementationOnly import _RegexParser extension Compiler { struct ByteCodeGen { @@ -26,19 +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.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)") } } } @@ -111,30 +114,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) + _CharacterClassModel.word.isBoundary( + 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) + !_CharacterClassModel.word.isBoundary( + input, at: pos, bounds: bounds, with: options) } } } @@ -288,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) @@ -306,7 +322,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) @@ -336,7 +352,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) @@ -348,10 +364,18 @@ extension Compiler.ByteCodeGen { mutating func emitQuantification( _ amount: AST.Quantification.Amount, - _ kind: AST.Quantification.Kind, + _ kind: DSLTree.QuantificationKind, _ child: DSLTree.Node ) throws { - let kind = kind.applying(options) + let updatedKind: AST.Quantification.Kind + switch kind { + case .explicit(let kind): + updatedKind = kind.ast + case .syntax(let kind): + updatedKind = kind.ast.applying(options) + case .default: + updatedKind = options.defaultQuantificationKind + } let (low, high) = amount.bounds switch (low, high) { @@ -480,7 +504,7 @@ extension Compiler.ByteCodeGen { } // Set up a dummy save point for possessive to update - if kind == .possessive { + if updatedKind == .possessive { builder.pushEmptySavePoint() } @@ -526,7 +550,7 @@ extension Compiler.ByteCodeGen { to: exit, ifZeroElseDecrement: extraTripsReg!) } - switch kind { + switch updatedKind { case .eager: builder.buildSplit(to: loopBody, saving: exit) case .possessive: @@ -561,8 +585,11 @@ extension Compiler.ByteCodeGen { try emitConcatenationComponent(child) } - case let .capture(_, refId, child): - let cap = builder.makeCapture(id: refId) + case let .capture(name, refId, child): + options.beginScope() + defer { options.endScope() } + + let cap = builder.makeCapture(id: refId, name: name) switch child { case let .matcher(_, m): emitMatcher(m, into: cap) @@ -575,16 +602,24 @@ 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): - 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) @@ -609,7 +644,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/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..47faa23ed 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 @@ -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/ConsumerInterface.swift b/Sources/_StringProcessing/ConsumerInterface.swift index 0a2d93ff1..a44c2c876 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 @@ -100,8 +100,12 @@ 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) + return try a.ast.generateConsumer(opts) } } @@ -136,7 +140,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) } } @@ -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 } @@ -287,105 +292,7 @@ extension DSLTree.CustomCharacterClass.Member { } case .trivia: // TODO: Should probably strip this earlier... - return { _, bounds in - return bounds.lowerBound - } - } - - } -} - -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 - } - } + return { _, _ in nil } } } } @@ -413,29 +320,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 @@ -539,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)") } }() @@ -811,8 +691,9 @@ extension Unicode.ExtendedGeneralCategory { ]) case .casedLetter: - throw Unsupported( - "TODO: cased letter? not the property?") + return consumeScalarGCs([ + .uppercaseLetter, .lowercaseLetter, .titlecaseLetter + ]) case .control: return consumeScalarGC(.control) 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/MEBuilder.swift b/Sources/_StringProcessing/Engine/MEBuilder.swift index 2b849874b..cae8194bd 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 { @@ -38,13 +38,12 @@ 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]] = [:] var referencedCaptureOffsets: [ReferenceID: Int] = [:] + var namedCaptureOffsets: [String: Int] = [:] var captureCount: Int { // We currently deduce the capture count from the capture register number. nextCaptureRegister.rawValue @@ -352,8 +351,9 @@ extension MEProgram.Builder { staticTransformFunctions: transformFunctions, staticMatcherFunctions: matcherFunctions, registerInfo: regInfo, - captureStructure: captureStructure, - referencedCaptureOffsets: referencedCaptureOffsets) + captureList: captureList, + referencedCaptureOffsets: referencedCaptureOffsets, + namedCaptureOffsets: namedCaptureOffsets) } mutating func reset() { self = Self() } @@ -438,7 +438,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 +448,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 301212736..e3a542c1e 100644 --- a/Sources/_StringProcessing/Engine/MECapture.swift +++ b/Sources/_StringProcessing/Engine/MECapture.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser /* @@ -142,9 +142,10 @@ extension Processor._StoredCapture: CustomStringConvertible { } } -struct CaptureList { +struct MECaptureList { 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 a31134cc9..8f1c721b0 100644 --- a/Sources/_StringProcessing/Engine/MEProgram.swift +++ b/Sources/_StringProcessing/Engine/MEProgram.swift @@ -9,16 +9,16 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly 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 @@ -34,8 +34,9 @@ struct MEProgram where Input.Element: Equatable { var enableTracing: Bool = false - let captureStructure: CaptureStructure + let captureList: CaptureList let referencedCaptureOffsets: [ReferenceID: Int] + let namedCaptureOffsets: [String: Int] } extension MEProgram: CustomStringConvertible { 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/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..a8cfeb20c 100644 --- a/Sources/_StringProcessing/Engine/Structuralize.swift +++ b/Sources/_StringProcessing/Engine/Structuralize.swift @@ -1,78 +1,21 @@ -import _RegexParser +@_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 148ddf468..e44b110e5 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 @@ -19,6 +19,7 @@ struct Executor { self.engine = Engine(program, enableTracing: enablesTracing) } + @available(SwiftStdlib 5.7, *) func match( _ input: String, in inputRange: Range, @@ -28,17 +29,19 @@ struct Executor { input: input, bounds: inputRange, matchMode: mode) guard let endIdx = cpu.consume() else { + if let e = cpu.failureReason { + throw e + } return nil } - let capList = CaptureList( + let capList = MECaptureList( values: cpu.storedCaptures, - referencedCaptureOffsets: engine.program.referencedCaptureOffsets) + referencedCaptureOffsets: engine.program.referencedCaptureOffsets, + namedCaptureOffsets: engine.program.namedCaptureOffsets) - let capStruct = engine.program.captureStructure let range = inputRange.lowerBound.., diff --git a/Sources/_StringProcessing/MatchingOptions.swift b/Sources/_StringProcessing/MatchingOptions.swift index 899891184..665715a60 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. @@ -22,6 +22,9 @@ struct MatchingOptions { // Must contain exactly one of each mutually exclusive group assert(stack.last!.intersection(.textSegmentOptions).rawValue.nonzeroBitCount == 1) assert(stack.last!.intersection(.semanticMatchingLevels).rawValue.nonzeroBitCount == 1) + + // Must contain at most one quantifier behavior + assert(stack.last!.intersection(.repetitionBehaviors).rawValue.nonzeroBitCount <= 1) } } @@ -63,15 +66,46 @@ extension MatchingOptions { stack.last!.contains(.reluctantByDefault) } + var defaultQuantificationKind: AST.Quantification.Kind { + if stack.last!.contains(.possessiveByDefault) { + return .possessive + } else if stack.last!.contains(.reluctantByDefault) { + return .reluctant + } else { + return .eager + } + } + var dotMatchesNewline: Bool { 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 { @@ -84,7 +118,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 @@ -129,6 +163,9 @@ extension MatchingOptions { case unicodeScalarSemantics case byteSemantics + // Swift-only default possessive quantifier + case possessiveByDefault + init?(_ astKind: AST.MatchingOption.Kind) { switch astKind { case .caseInsensitive: @@ -163,6 +200,8 @@ extension MatchingOptions { self = .unicodeScalarSemantics case .byteSemantics: self = .byteSemantics + case .possessiveByDefault: + self = .possessiveByDefault // Whitespace options are only relevant during parsing, not compilation. case .extended, .extraExtended: @@ -198,6 +237,9 @@ extension MatchingOptions { if Self.textSegmentOptions.contains(opt.representation) { remove(.textSegmentOptions) } + if Self.repetitionBehaviors.contains(opt.representation) { + remove(.repetitionBehaviors) + } insert(opt.representation) } @@ -220,6 +262,9 @@ extension MatchingOptions { guard let opt = Option(opt.kind) else { continue } + if Self.repetitionBehaviors.contains(opt.representation) { + remove(.repetitionBehaviors) + } remove(opt.representation) } } @@ -253,7 +298,15 @@ extension MatchingOptions.Representation { static var semanticMatchingLevels: Self { [.graphemeClusterSemantics, .unicodeScalarSemantics, .byteSemantics] } - + + // Quantification behavior options + static var reluctantByDefault: Self { .init(.reluctantByDefault) } + static var possessiveByDefault: Self { .init(.possessiveByDefault) } + + static var repetitionBehaviors: Self { + [.reluctantByDefault, .possessiveByDefault] + } + /// The default set of options. static var `default`: Self { [.graphemeClusterSemantics, .textSegmentGraphemeMode] diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index 0cf16ab05..1b5c2a4c5 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,8 +17,10 @@ import _RegexParser // incremental conversion, such that leaves remain // as canonical regex literals. +@_spi(PatternConverter) extension AST { - /// Render as a Pattern DSL + /// Renders as a Pattern DSL. + @_spi(PatternConverter) public func renderAsBuilderDSL( maxTopDownLevels: Int? = nil, minBottomUpLevels: Int? = nil @@ -55,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 references 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 @@ -66,7 +78,7 @@ extension PrettyPrinter { private mutating func printAsPattern( convertedFromAST node: DSLTree.Node ) { - if patternBackoff(node) { + if patternBackoff(DSLTree._Tree(node)) { printBackoff(node) return } @@ -74,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._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) @@ -106,40 +121,39 @@ extension PrettyPrinter { print("/* TODO: conditional */") case let .quantification(amount, kind, child): - let amount = amount._patternBase - let kind = kind._patternBase - printBlock("\(amount)(\(kind))") { printer in + let amount = amount.ast._patternBase + 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._patternBase) - - case .assertion: - print("/* TODO: assertions */") - case .backreference: - print("/* TOOD: backreferences */") - case .symbolicReference: - print("/* TOOD: symbolic references */") + 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("") @@ -176,11 +190,135 @@ 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 = "" + + + // 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): + 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(")") } } @@ -190,73 +328,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 + } } } @@ -274,6 +663,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) @@ -283,21 +680,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 */" @@ -318,51 +756,64 @@ extension AST.Atom { case .backtrackingDirective: return " /* TODO: backtracking directive */" + + 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 */" } } } @@ -372,11 +823,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))" } } } @@ -390,3 +841,148 @@ extension AST.Quantification.Kind { } } } + +extension DSLTree.QuantificationKind { + var _patternBase: String { + (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 + } +} diff --git a/Sources/_StringProcessing/Regex/ASTConversion.swift b/Sources/_StringProcessing/Regex/ASTConversion.swift index 5336a1892..ef98a7b8f 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 { @@ -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, 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,16 +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 .char(c): return .char(c) + case let .scalar(s): return .scalar(s) + case .any: return .any + case let .backreference(r): return .backreference(.init(ast: r)) + case let .changeMatchingOptions(seq): return .changeMatchingOptions(.init(ast: seq)) - default: return .unconverted(self) + case .escaped(let c) where c.scalarValue != nil: + return .scalar(c.scalarValue!) + + default: return .unconverted(.init(ast: self)) } } } diff --git a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift index cac0e46c3..00fc2e952 100644 --- a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift +++ b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift @@ -9,36 +9,51 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly 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 { + /// 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)) } } +@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( - compiling pattern: String, + _ pattern: String, as: Output.Type = Output.self ) throws { self.init(ast: try parse(pattern, .traditional)) } } +@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 { 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 @@ -47,16 +62,18 @@ public struct AnyRegexOutput { /// The depth of `Optioals`s wrapping the underlying value. For example, /// `Substring` has optional depth `0`, and `Int??` has optional depth `2`. let optionalDepth: Int + /// The bounds of the output element. let bounds: Range? } } +@available(SwiftStdlib 5.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. @@ -70,10 +87,11 @@ 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. - public func `as`(_ type: Output.Type) -> Output? { + /// output type; otherwise `nil`. + public func `as`(_ type: Output.Type = Output.self) -> Output? { let elements = _elements.map { StructuredCapture( optionalCount: $0.optionalDepth, @@ -84,14 +102,19 @@ 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)) } } +@available(SwiftStdlib 5.7, *) extension AnyRegexOutput.ElementRepresentation { init(_ element: StructuredCapture) { self.init( @@ -114,18 +137,26 @@ extension AnyRegexOutput.ElementRepresentation { } } +@available(SwiftStdlib 5.7, *) extension AnyRegexOutput: RandomAccessCollection { public struct Element { 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 +183,65 @@ extension AnyRegexOutput: RandomAccessCollection { .init(representation: _elements[position], input: input) } } + +@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. + /// + /// Use this initializer to fit a regex match with strongly typed captures into the + /// use site of a dynamic regex match, like 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; otherwise, `nil`. + public func `as`( + _ type: Output.Type = Output.self + ) -> Regex.Match? { + fatalError("FIXME: Not implemented") + } +} + +@available(SwiftStdlib 5.7, *) +extension Regex { + /// Returns whether a named-capture with `name` exists + public func contains(captureNamed name: String) -> Bool { + program.tree.root._captureList.captures.contains(where: { + $0.name == name + }) + } +} + +@available(SwiftStdlib 5.7, *) +extension Regex where Output == AnyRegexOutput { + /// 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(_ regex: 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 = Output.self + ) -> Regex? { + fatalError("FIXME: Not implemented") + } +} diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index 265a7868c..1f9a35dad 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -9,22 +9,24 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser /// A type that represents a regular expression. +@available(SwiftStdlib 5.7, *) public protocol RegexComponent { - associatedtype Output - var regex: Regex { get } + associatedtype RegexOutput + var regex: Regex { get } } -/// A regex represents a string processing algorithm. +/// A regular expression. /// -/// 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" /// +@available(SwiftStdlib 5.7, *) public struct Regex: RegexComponent { let program: Program @@ -59,6 +61,14 @@ 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 /// execution. @@ -83,6 +93,7 @@ extension Regex { } } +@available(SwiftStdlib 5.7, *) extension Regex { @_spi(RegexBuilder) public var root: DSLTree.Node { @@ -93,60 +104,4 @@ extension Regex { public init(node: DSLTree.Node) { self.program = Program(tree: .init(node, options: nil)) } - -} - -// 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: - 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/Regex/CustomComponents.swift b/Sources/_StringProcessing/Regex/CustomComponents.swift new file mode 100644 index 000000000..d675c3ae7 --- /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 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: + /// - 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 CustomConsumingRegexComponent { + 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 8d64f8355..000000000 --- a/Sources/_StringProcessing/Regex/DSLConsumers.swift +++ /dev/null @@ -1,26 +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 -// -//===----------------------------------------------------------------------===// - -public protocol CustomRegexComponent: RegexComponent { - func match( - _ input: String, - startingAt index: String.Index, - in bounds: Range - ) -> (upperBound: String.Index, output: Output)? -} - -extension CustomRegexComponent { - public var regex: Regex { - Regex(node: .matcher(.init(Output.self), { input, index, bounds in - match(input, startingAt: index, in: bounds) - })) - } -} diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index bd3b37a3d..b279c08e4 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 { @@ -24,46 +24,46 @@ public struct DSLTree { extension DSLTree { @_spi(RegexBuilder) - public indirect enum Node: _TreeNode { - /// Try to match each node in order + public indirect enum Node { + /// 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 - case nonCapturingGroup(AST.Group.Kind, Node) + /// 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) /// case conditional( - AST.Conditional.Condition.Kind, Node, Node) + _AST.ConditionKind, Node, Node) case quantification( - AST.Quantification.Amount, - AST.Quantification.Kind, + _AST.QuantificationAmount, + QuantificationKind, Node) case customCharacterClass(CustomCharacterClass) 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,20 +73,20 @@ extension DSLTree { case quotedLiteral(String) - /// An embedded literal - case regexLiteral(AST.Node) + /// An embedded literal. + 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) @@ -103,12 +103,59 @@ extension DSLTree { } extension DSLTree { + @_spi(RegexBuilder) + public enum QuantificationKind { + /// The default quantification kind, as set by options. + case `default` + /// An explicitly chosen kind, overriding any options. + case explicit(_AST.QuantificationKind) + /// A kind set via syntax, which can be affected by options. + 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) 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 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() + return result + } - enum Member { + @_spi(RegexBuilder) + public enum Member { case atom(Atom) case range(Atom, Atom) case custom(CustomCharacterClass) @@ -129,11 +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 unconverted(AST.Atom) + case changeMatchingOptions(_AST.MatchingOptionSequence) + + 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 + } } } @@ -141,14 +228,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) @@ -191,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) } } } @@ -200,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 } } @@ -245,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: @@ -256,108 +343,355 @@ extension DSLTree.Node { } } -extension DSLTree { - var captureStructure: CaptureStructure { - // TODO: nesting - var constructor = CaptureStructure.Constructor(.flatten) - return root._captureStructure(&constructor) +extension DSLTree.Node { + /// For typed capture-producing nodes, the type produced. + var valueCaptureType: AnyType? { + switch self { + case let .matcher(t, _): + return AnyType(t) + case let .transform(t, _): + return AnyType(t.resultType) + default: return nil + } } } + extension DSLTree.Node { @_spi(RegexBuilder) - public func _captureStructure( - _ constructor: inout CaptureStructure.Constructor - ) -> CaptureStructure { + public func appending(_ newNode: DSLTree.Node) -> DSLTree.Node { + if case .concatenation(let components) = self { + return .concatenation(components + [newNode]) + } + return .concatenation([self, newNode]) + } + + @_spi(RegexBuilder) + public func appendingAlternationCase( + _ newNode: DSLTree.Node + ) -> DSLTree.Node { + if case .orderedChoice(let components) = self { + return .orderedChoice(components + [newNode]) + } + return .orderedChoice([self, newNode]) + } +} + +@_spi(RegexBuilder) +public struct ReferenceID: Hashable, Equatable { + private static var counter: Int = 0 + var base: Int + + public init() { + base = Self.counter + 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 { + "" + } +} + +// 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.Node { + func _addCaptures( + to list: inout CaptureList, + optionalNesting nesting: Int + ) { + let addOptional = nesting+1 switch self { case let .orderedChoice(children): - return constructor.alternating(children) + for child in children { + child._addCaptures(to: &list, optionalNesting: addOptional) + } case let .concatenation(children): - return constructor.concatenating(children) + for child in children { + child._addCaptures(to: &list, optionalNesting: nesting) + } case let .capture(name, _, child): - if let type = child.valueCaptureType { - return constructor.capturing( - name: name, child, withType: type) - } - return constructor.capturing(name: name, child) + list.append(.init( + name: name, + type: child.valueCaptureType?.base, + optionalDepth: nesting)) + child._addCaptures(to: &list, optionalNesting: nesting) case let .nonCapturingGroup(kind, child): - assert(!kind.isCapturing) - return constructor.grouping(child, as: kind) + assert(!kind.ast.isCapturing) + child._addCaptures(to: &list, optionalNesting: nesting) case let .conditional(cond, trueBranch, falseBranch): - return constructor.condition( - cond, - trueBranch: trueBranch, - falseBranch: falseBranch) + switch cond.ast { + case .group(let g): + AST.Node.group(g)._addCaptures(to: &list, optionalNesting: nesting) + default: + break + } + + trueBranch._addCaptures(to: &list, optionalNesting: addOptional) + falseBranch._addCaptures(to: &list, optionalNesting: addOptional) + case let .quantification(amount, _, child): - return constructor.quantifying( - child, amount: amount) + var optNesting = nesting + if amount.ast.bounds.atLeast == 0 { + optNesting += 1 + } + child._addCaptures(to: &list, optionalNesting: optNesting) case let .regexLiteral(re): - // TODO: Force a re-nesting? - return re._captureStructure(&constructor) + return re.ast._addCaptures(to: &list, optionalNesting: nesting) case let .absentFunction(abs): - return constructor.absent(abs.kind) + switch abs.ast.kind { + case .expression(_, _, let child): + child._addCaptures(to: &list, optionalNesting: nesting) + case .clearer, .repeater, .stopper: + break + @unknown default: + fatalError() + } case let .convertedRegexLiteral(n, _): - // TODO: Switch nesting strategy? - return n._captureStructure(&constructor) + return n._addCaptures(to: &list, optionalNesting: nesting) case .matcher: - return .empty + break case .transform(_, let child): - return child._captureStructure(&constructor) + child._addCaptures(to: &list, optionalNesting: nesting) case .customCharacterClass, .atom, .trivia, .empty, .quotedLiteral, .consumer, .characterPredicate: - return .empty + break } } - /// For typed capture-producing nodes, the type produced. - var valueCaptureType: AnyType? { - switch self { - case let .matcher(t, _): - return t - case let .transform(t, _): - return AnyType(t.resultType) - default: return nil - } + var _captureList: CaptureList { + var list = CaptureList() + self._addCaptures(to: &list, optionalNesting: 0) + return list } } -extension DSLTree.Node { - @_spi(RegexBuilder) - public func appending(_ newNode: DSLTree.Node) -> DSLTree.Node { - if case .concatenation(let components) = self { - return .concatenation(components + [newNode]) +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) + } } - return .concatenation([self, newNode]) } @_spi(RegexBuilder) - public func appendingAlternationCase( - _ newNode: DSLTree.Node - ) -> DSLTree.Node { - if case .orderedChoice(let components) = self { - return .orderedChoice(components + [newNode]) + 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) + } } - return .orderedChoice([self, newNode]) - } -} -@_spi(RegexBuilder) -public struct ReferenceID: Hashable, Equatable { - private static var counter: Int = 0 - var base: Int - - public init() { - base = Self.counter - Self.counter += 1 + @_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/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 45d33f03e..8172e993b 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. /// @@ -18,19 +19,22 @@ 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] let referencedCaptureOffsets: [ReferenceID: Int] + let namedCaptureOffsets: [String: Int] + let value: Any? } } +@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( @@ -38,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 { @@ -57,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> @@ -81,46 +86,53 @@ extension Regex.Match { } } -extension RegexComponent { - /// Match a string in its entirety. +@available(SwiftStdlib 5.7, *) +extension Regex { + /// Matches a string in its entirety. /// - /// Returns `nil` if no match and throws on abort - public func matchWhole(_ s: String) throws -> Regex.Match? { + /// - 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? { + /// - Parameter s: The string to match this regular expression against. + /// - Returns: The match, or `nil` if no match was found. + public func prefixMatch(in s: String) throws -> Regex.Match? { try _match(s, in: s.startIndex.. Regex.Match? { try _firstMatch(s, in: s.startIndex.. Regex.Match? { + /// - Parameter s: The substring to match this regular expression against. + /// - Returns: The match, or `nil` if no match was found. + public func wholeMatch(in s: Substring) throws -> Regex.Match? { try _match(s.base, in: s.startIndex.. Regex.Match? { + /// - Parameter s: The substring to match this regular expression against. + /// - Returns: The match, or `nil` if no match was found. + public func prefixMatch(in s: Substring) throws -> Regex.Match? { try _match(s.base, in: s.startIndex.. Regex.Match? { + /// - Parameter s: The substring to match this regular expression against. + /// - Returns: The match, or `nil` if no match was found. + public func firstMatch(in s: Substring) throws -> Regex.Match? { try _firstMatch(s.base, in: s.startIndex.. 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( @@ -152,19 +164,36 @@ extension RegexComponent { } } -extension String { - public func matchWhole(_ regex: R) -> Regex.Match? { - try? regex.matchWhole(self) +@available(SwiftStdlib 5.7, *) +extension BidirectionalCollection where SubSequence == Substring { + /// Checks for a match against the string in its entirety. + /// + /// - Parameter r: The regular expression being matched. + /// - Returns: The match, or `nil` if no match was found. + public func wholeMatch( + of r: R + ) -> Regex.Match? { + try? r.regex.wholeMatch(in: self[...].base) } - public func matchPrefix(_ regex: R) -> Regex.Match? { - try? regex.matchPrefix(self) + + /// 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? { + try? r.regex.prefixMatch(in: self[...]) } } -extension Substring { - public func matchWhole(_ regex: R) -> Regex.Match? { - try? regex.matchWhole(self) + +@available(SwiftStdlib 5.7, *) +extension RegexComponent { + public static func ~=(regex: Self, input: String) -> Bool { + input.wholeMatch(of: regex) != nil } - public func matchPrefix(_ regex: R) -> Regex.Match? { - try? regex.matchPrefix(self) + + public static func ~=(regex: Self, input: Substring) -> Bool { + input.wholeMatch(of: regex) != nil } } diff --git a/Sources/_StringProcessing/Regex/Options.swift b/Sources/_StringProcessing/Regex/Options.swift index 04be79c6e..24d5c422e 100644 --- a/Sources/_StringProcessing/Regex/Options.swift +++ b/Sources/_StringProcessing/Regex/Options.swift @@ -9,20 +9,269 @@ // //===----------------------------------------------------------------------===// -import _RegexParser +@_implementationOnly import _RegexParser +@available(SwiftStdlib 5.7, *) 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)]) - return Regex(node: .nonCapturingGroup( - .changeMatchingOptions(sequence, isIsolated: false), - regex.root)) + /// 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 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 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 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 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) + } + + /// 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. + /// - Returns: The modified regular expression. + public func dotMatchesNewlines(_ dotMatchesNewlines: Bool = true) -> Regex { + wrapInOption(.singleLine, addingIf: dotMatchesNewlines) + } + + /// 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 regex syntax. 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. + /// - Returns: The modified regular expression. + public func anchorsMatchLineEndings(_ matchLineEndings: Bool = true) -> Regex { + wrapInOption(.multiline, addingIf: matchLineEndings) + } + + /// Returns a regular expression where quantifiers use the specified behavior + /// by default. + /// + /// This setting does not affect calls to quantifier methods, such as + /// `OneOrMore`, that include an explicit `behavior` parameter. + /// + /// 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 + /// 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" + /// + /// - Parameter semanticLevel: The semantics to use during matching. + /// - Returns: The modified regular expression. + public func matchingSemantics(_ semanticLevel: RegexSemanticLevel) -> Regex { + switch semanticLevel.base { + case .graphemeCluster: + return wrapInOption(.graphemeClusterSemantics, addingIf: true) + case .unicodeScalar: + return wrapInOption(.unicodeScalarSemantics, addingIf: true) + } } } +@available(SwiftStdlib 5.7, *) +/// A semantic level to use during regex matching. +public struct RegexSemanticLevel: Hashable { + internal enum Representation { + case graphemeCluster + case unicodeScalar + } + + internal var base: Representation + + /// 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 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) + } +} + +@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) + } +} + +/// 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, *) +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( + .init(ast: .changeMatchingOptions(sequence)), regex.root)) + } +} 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/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) - } -} 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) - } -} - diff --git a/Sources/_StringProcessing/Utility/ASTBuilder.swift b/Sources/_StringProcessing/Utility/ASTBuilder.swift index 8a9af8111..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( @@ -106,22 +106,27 @@ 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( - _ 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( @@ -354,6 +359,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/Sources/_StringProcessing/CharacterClass.swift b/Sources/_StringProcessing/_CharacterClassModel.swift similarity index 65% rename from Sources/_StringProcessing/CharacterClass.swift rename to Sources/_StringProcessing/_CharacterClassModel.swift index d44fa9fb2..4d0c12c1f 100644 --- a/Sources/_StringProcessing/CharacterClass.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -9,13 +9,14 @@ // //===----------------------------------------------------------------------===// -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 // 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 @@ -32,6 +33,8 @@ public struct CharacterClass: Hashable { case any /// Any grapheme cluster case anyGrapheme + /// Any Unicode scalar + case anyScalar /// Character.isDigit case digit /// Character.isHexDigit @@ -51,7 +54,11 @@ public struct CharacterClass: 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 { @@ -59,14 +66,14 @@ public struct CharacterClass: Hashable { var op: SetOperator var rhs: CharacterSetComponent - public func matches(_ c: Character) -> Bool { + 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) } } } @@ -76,7 +83,7 @@ public struct CharacterClass: Hashable { 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) @@ -87,87 +94,122 @@ public struct CharacterClass: Hashable { .setOperation(.init(lhs: lhs, op: op, rhs: rhs)) } - public func matches(_ character: Character) -> Bool { + 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) } } } - 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 } - /// Returns an inverted character class if true is passed, otherwise the - /// same character class is returned. - public 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. - public func matches(in str: String, at i: String.Index) -> String.Index? { + /// 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: let c = str[i] var matched: Bool + var next = str.index(after: i) switch cc { case .any, .anyGrapheme: matched = true - case .digit: matched = c.isNumber - case .hexDigit: matched = c.isHexDigit + case .anyScalar: + matched = true + next = str.unicodeScalars.index(after: i) + 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() } - 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 - 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 { @@ -178,10 +220,11 @@ public struct CharacterClass: Hashable { } } -extension CharacterClass: RegexComponent { - public typealias Output = Substring +@available(SwiftStdlib 5.7, *) +extension _CharacterClassModel: RegexComponent { + public typealias RegexOutput = Substring - public var regex: Regex { + public var regex: Regex { guard let ast = self.makeAST() else { fatalError("FIXME: extended AST?") } @@ -189,51 +232,56 @@ 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 anyUnicodeScalar: _CharacterClassModel { + .init(cc: .any, matchLevel: .unicodeScalar) + } + + 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 "" @@ -244,11 +292,12 @@ extension CharacterClass.CharacterSetComponent: CustomStringConvertible { } } -extension CharacterClass.Representation: CustomStringConvertible { +extension _CharacterClassModel.Representation: CustomStringConvertible { public var description: String { switch self { case .any: return "" case .anyGrapheme: return "" + case .anyScalar: return "" case .digit: return "" case .hexDigit: return "" case .horizontalWhitespace: return "" @@ -261,14 +310,24 @@ extension CharacterClass.Representation: CustomStringConvertible { } } -extension CharacterClass: CustomStringConvertible { +extension _CharacterClassModel: CustomStringConvertible { public var description: String { return "\(isInverted ? "not " : "")\(cc)" } } -extension CharacterClass { - public func makeAST() -> AST.Node? { +extension _CharacterClassModel { + 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 { @@ -320,7 +379,7 @@ extension CharacterClass { } extension DSLTree.Node { - var characterClass: CharacterClass? { + var characterClass: _CharacterClassModel? { switch self { case let .customCharacterClass(ccc): return ccc.modelCharacterClass @@ -335,10 +394,10 @@ extension DSLTree.Node { } } -extension CharacterClass { - public func withMatchLevel( - _ level: CharacterClass.MatchLevel - ) -> CharacterClass { +extension _CharacterClassModel { + func withMatchLevel( + _ level: _CharacterClassModel.MatchLevel + ) -> _CharacterClassModel { var cc = self cc.matchLevel = level return cc @@ -346,10 +405,10 @@ extension CharacterClass { } extension DSLTree.Atom { - var characterClass: CharacterClass? { + var characterClass: _CharacterClassModel? { switch self { case let .unconverted(a): - return a.characterClass + return a.ast.characterClass default: return nil } @@ -357,7 +416,7 @@ extension DSLTree.Atom { } extension AST.Atom { - var characterClass: CharacterClass? { + var characterClass: _CharacterClassModel? { switch kind { case let .escaped(b): return b.characterClass @@ -383,7 +442,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 @@ -405,6 +464,7 @@ extension AST.Atom.EscapedBuiltin { case .notWordCharacter: return .word.inverted case .graphemeCluster: return .anyGrapheme + case .trueAnychar: return .anyUnicodeScalar default: return nil @@ -414,9 +474,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): @@ -482,12 +542,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 @@ -495,21 +555,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/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 diff --git a/Tests/RegexBuilderTests/AlgorithmsTests.swift b/Tests/RegexBuilderTests/AlgorithmsTests.swift index 183d247a7..173d41598 100644 --- a/Tests/RegexBuilderTests/AlgorithmsTests.swift +++ b/Tests/RegexBuilderTests/AlgorithmsTests.swift @@ -11,13 +11,14 @@ import XCTest import _StringProcessing -@testable import RegexBuilder +import RegexBuilder +@available(SwiftStdlib 5.7, *) 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]) + XCTAssertEqual(str.matches(of: regex).map(\.output.1), [320, 198]) } func testMatchReplace() { @@ -25,7 +26,7 @@ class RegexConsumerTests: XCTestCase { _ regex: R, input: String, result: String, - _ replace: (_MatchResult>) -> String, + _ replace: (Regex.Match) -> String, file: StaticString = #file, line: UInt = #line ) { @@ -38,13 +39,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 +58,446 @@ 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))" }) + } + + func testMatchReplaceSubrange() { + func replaceTest( + _ 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..( + _ 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.. Output? +private protocol Nibbler: CustomConsumingRegexComponent { + 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 - ) -> (upperBound: String.Index, output: Output)? { + ) throws -> (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,12 +43,75 @@ 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 } } +private struct IntParser: CustomConsumingRegexComponent { + struct ParseError: Error, Hashable {} + typealias RegexOutput = Int + func consuming(_ 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..( 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)?.result + result = input.firstMatch(of: regex)?.output } XCTAssertEqual(result, match) } } +// 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. - func testCustomRegexComponents() { + func testCustomRegexComponents() throws { customTest( Regex { Numbler() @@ -115,14 +223,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.match, "123") - XCTAssertEqual(res3.result.0, "123") - XCTAssertEqual(res3.result.1, "123") + let expectedSubstring = str.dropFirst(2).prefix(3) + XCTAssertEqual(res3.range, expectedSubstring.startIndex.. 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.wholeMatch(in: "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.wholeMatch(in: "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.wholeMatch(in: "0x1234567f") else { + XCTFail() + return + } + XCTAssertEqual(m.0, "0x1234567f") + XCTAssertEqual(m.1, 0x1234567f) + } catch { + XCTFail() + } + + do { + _ = try addressRegex.wholeMatch(in: "0xdeadbeef") + XCTFail() + } catch let e as Poison { + XCTAssertEqual(e, Poison()) + } catch { + XCTFail() + } + + + } + + func testCustomRegexThrows() { + + func customTest( + _ 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()) + ) + + } + + + 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)) } } + diff --git a/Tests/RegexBuilderTests/MotivationTests.swift b/Tests/RegexBuilderTests/MotivationTests.swift index 882ba6448..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 @@ -139,24 +135,26 @@ private func processWithRuntimeDynamicRegex( _ line: String ) -> Transaction? { // FIXME: Shouldn't this init throw? - let regex = try! Regex(compiling: pattern) - -// 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) + 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 + } - return nil + return Transaction( + kind: kind, date: date, account: account, amount: amount) } @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) } @@ -199,7 +197,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 @@ -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 50358734d..5673aa348 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( @@ -24,14 +24,14 @@ 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( - 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,13 +51,13 @@ class RegexDSLTests: XCTestCase { TryCapture("1") { Int($0) } // Int } // Assert the inferred capture type. - let _: (Substring, Substring, Int).Type = type(of: regex).Output.self - let maybeMatch = "ab1".matchWhole(regex) + 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)) let substring = "ab1"[...] - let substringMatch = try XCTUnwrap(substring.matchWhole(regex)) + let substringMatch = try XCTUnwrap(substring.wholeMatch(of: regex)) XCTAssertTrue(match.output == substringMatch.output) } @@ -70,10 +70,63 @@ 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") + NegativeLookahead(disallowedChars) // 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 { - let match = try XCTUnwrap("aaa".matchWhole { OneOrMore { "a" } }) + let match = try XCTUnwrap("aaa".wholeMatch { OneOrMore { "a" } }) XCTAssertEqual(match.0, "aaa") } @@ -82,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 { @@ -91,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 { @@ -109,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 { @@ -117,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 { @@ -137,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) } } @@ -175,7 +228,7 @@ class RegexDSLTests: XCTestCase { matchType: Substring.self, ==) { OneOrMore { "abc" - }.caseSensitive(false) + }.ignoresCase(true) } // Multiple options on one component wrap successively, but do not @@ -189,8 +242,8 @@ class RegexDSLTests: XCTestCase { OneOrMore { "abc" } - .caseSensitive(false) - .caseSensitive(true) + .ignoresCase(true) + .ignoresCase(false) } // An option on an outer component doesn't override an option set on an @@ -204,46 +257,165 @@ class RegexDSLTests: XCTestCase { ("abcdeABCdeaBcde", "abcdeABCdeaBcde"), matchType: Substring.self, ==) { OneOrMore { - "abc".caseSensitive(false) + "abc".ignoresCase(true) Optionally("de") } - .caseSensitive(true) + .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, .reluctant) + "stop" + " " + + Capture { + OneOrMore(.word) + Anchor.wordBoundary + } + .wordBoundaryKind(.unicodeLevel1) + OneOrMore(.any, .reluctant) + "stop" + } + } +#endif + + try _testDSLCaptures( + ("abcdef123", ("abcdef123", "a", "123")), + matchType: (Substring, Substring, Substring).self, ==) { + Capture { + // Reluctant behavior due to option + OneOrMore(.anyOf("abcd")) + .repetitionBehavior(.reluctant) + } + ZeroOrMore("a"..."z") + + Capture { + // Eager behavior due to explicit parameter, despite option + OneOrMore(.digit, .eager) + .repetitionBehavior(.reluctant) + } + 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 { + // Eager by default try _testDSLCaptures( ("abc1def2", ("abc1def2", "2")), matchType: (Substring, Substring).self, ==) { - OneOrMore { - OneOrMore(.word) - Capture(.digit) - } + OneOrMore(.word) + Capture(.digit) + ZeroOrMore(.any) } + // Explicitly reluctant try _testDSLCaptures( - ("abc1def2", ("abc1def2", "2")), + ("abc1def2", ("abc1def2", "1")), matchType: (Substring, Substring).self, ==) { - OneOrMore { - OneOrMore(.word, .reluctantly) + OneOrMore(.word, .reluctant) + Capture(.digit) + ZeroOrMore(.any) + } + // Explicitly reluctant overrides default option + try _testDSLCaptures( + ("abc1def2", ("abc1def2", "1")), + matchType: (Substring, Substring).self, ==) + { + 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( - ("abc1def2", ("abc1def2", "2")), + ("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, ==) { - OneOrMore { - OneOrMore(.reluctantly) { - .word + Regex { + Capture { + OneOrMore("a") + .repetitionBehavior(.eager) } - Capture(.digit) - } + 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, ==) @@ -273,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 { @@ -307,7 +487,7 @@ class RegexDSLTests: XCTestCase { { OneOrMore("a") Lookahead(CharacterClass.digit) - Lookahead("2", negative: true) + NegativeLookahead { "2" } CharacterClass.word } } @@ -340,9 +520,9 @@ 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.matchWhole(regex)?.output) + let match = try XCTUnwrap(input.wholeMatch(of: regex)?.output) XCTAssertTrue(match == input) } @@ -389,7 +569,8 @@ class RegexDSLTests: XCTestCase { } } let _: (Substring, Substring, Substring).Type - = type(of: regex1).Output.self + = type(of: regex1).RegexOutput.self + let regex2 = Regex { OneOrMore("a") Capture { @@ -400,7 +581,8 @@ class RegexDSLTests: XCTestCase { } } let _: (Substring, Substring, Int?).Type - = type(of: regex2).Output.self + = type(of: regex2).RegexOutput.self + let regex3 = Regex { OneOrMore("a") Capture { @@ -412,7 +594,8 @@ 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 { @@ -426,7 +609,7 @@ class RegexDSLTests: XCTestCase { } let _: ( Substring, Substring, Substring, Substring, Substring?).Type - = type(of: regex4).Output.self + = type(of: regex4).RegexOutput.self } func testUnicodeScalarPostProcessing() throws { @@ -465,11 +648,11 @@ 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" - let match = try XCTUnwrap(unicodeLine.matchWhole(unicodeData)) + let match = try XCTUnwrap(unicodeLine.wholeMatch(of: unicodeData)) XCTAssertEqual(match.0, Substring(unicodeLine)) XCTAssertEqual(match.1, "Control") } @@ -500,8 +683,8 @@ class RegexDSLTests: XCTestCase { typealias ExpectedMatch = ( Substring, Unicode.Scalar?, Unicode.Scalar??, Substring ) - let _: ExpectedMatch.Type = type(of: regexWithCapture).Output.self - let maybeMatchResult = line.matchWhole(regexWithCapture) + 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 XCTAssertEqual(wholeMatch, Substring(line)) @@ -535,8 +718,8 @@ class RegexDSLTests: XCTestCase { typealias ExpectedMatch = ( Substring, Unicode.Scalar, Unicode.Scalar?, Substring ) - let _: ExpectedMatch.Type = type(of: regexWithTryCapture).Output.self - let maybeMatchResult = line.matchWhole(regexWithTryCapture) + 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 XCTAssertEqual(wholeMatch, Substring(line)) @@ -546,10 +729,10 @@ class RegexDSLTests: XCTestCase { } do { - let regexLiteral = try MockRegexLiteral( - #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, - matching: (Substring, Substring, Substring?, Substring).self) - let maybeMatchResult = line.matchWhole(regexLiteral) + let regexLiteral = try Regex( + #"([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) let (wholeMatch, lower, upper, propertyString) = matchResult.output XCTAssertEqual(wholeMatch, Substring(line)) @@ -559,38 +742,6 @@ class RegexDSLTests: XCTestCase { } } - func testDynamicCaptures() throws { - do { - let regex = try Regex(compiling: "aabcc.") - let line = "aabccd" - let match = try XCTUnwrap(line.matchWhole(regex)) - XCTAssertEqual(match.0, line[...]) - let output = match.output - XCTAssertEqual(output[0].substring, line[...]) - } - do { - let regex = try Regex( - 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 - """ - let match = try XCTUnwrap(line.matchWhole(regex)) - XCTAssertEqual(match.0, line[...]) - let output = match.output - XCTAssertEqual(output[0].substring, line[...]) - XCTAssertTrue(output[1].substring == "A6F0") - XCTAssertTrue(output[2].substring == "A6F1") - XCTAssertTrue(output[3].substring == "Extend") - let typedOutput = try XCTUnwrap(output.as( - (Substring, Substring, Substring?, Substring).self)) - XCTAssertEqual(typedOutput.0, line[...]) - XCTAssertTrue(typedOutput.1 == "A6F0") - XCTAssertTrue(typedOutput.2 == "A6F1") - XCTAssertTrue(typedOutput.3 == "Extend") - } - } - func testBackreference() throws { try _testDSLCaptures( ("abc#41#42abcabcabc", ("abc#41#42abcabcabc", "abc", 42, "abc", nil)), @@ -640,11 +791,43 @@ 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) } + 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( @@ -678,13 +861,13 @@ class RegexDSLTests: XCTestCase { var patch: Int var dev: String? } - struct SemanticVersionParser: CustomRegexComponent { - typealias Output = SemanticVersion - func match( + struct SemanticVersionParser: CustomConsumingRegexComponent { + typealias RegexOutput = SemanticVersion + func consuming( _ 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) } "." @@ -704,23 +887,23 @@ 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) } } - + 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.matchWhole(parser)?.output, version) + XCTAssertEqual(str.wholeMatch(of: parser)?.output, version) } } } 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)..(_ s: @autoclosure () -> T) { } } -class RegexConsumerTests: XCTestCase { +func makeSingleUseSequence(element: T, count: Int) -> UnfoldSequence { + var count = count + return sequence(state: ()) { _ in + defer { count -= 1 } + return count > 0 ? element : nil + } +} + +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, @@ -32,22 +58,17 @@ 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 { - 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) + + 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() { @@ -77,16 +123,154 @@ class RegexConsumerTests: XCTestCase { _ expected: [Substring], file: StaticString = #file, line: UInt = #line ) { - let regex = try! Regex(compiling: regex) - let actual = Array(string.split(by: regex)) + let regex = try! Regex(regex) + let actual = Array(string.split(separator: regex, omittingEmptySubsequences: false)) 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) + let splitParamsRef = "abcd".split(separator:maxSplits:omittingEmptySubsequences:) + XCTAssert(type(of: splitParamsRef) == ((Character, Int, Bool) -> [Substring]).self) + } + + 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( + _ 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() { @@ -97,7 +281,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) } @@ -115,34 +299,53 @@ class RegexConsumerTests: XCTestCase { expectReplace("aab", "a*", "X", "XXbX") } - func testAdHoc() { - let r = try! Regex(compiling: "a|b+") + 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("a+") - XCTAssert("palindrome".contains(r)) - XCTAssert("botany".contains(r)) - XCTAssert("antiquing".contains(r)) - XCTAssertFalse("cdef".contains(r)) + XCTAssertEqual(s.firstMatch(of: regex)?.0, "aaa") + XCTAssertEqual(s1.firstMatch(of: regex)?.0, "aaaaaa") + XCTAssertEqual(s2.firstMatch(of: regex)?.0, "aa") - 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)...Match, + _ concrete: Regex<(Substring, fieldA: Substring, fieldB: Substring)>.Match +) { + checkSame(aro.output, concrete.output) + + XCTAssertEqual(aro.0, concrete.0) + XCTAssertEqual(aro[0].substring, concrete.0) + + XCTAssertEqual(aro["fieldA"]!.substring, concrete.1) + XCTAssertEqual(aro["fieldA"]!.substring, concrete.fieldA) + XCTAssertEqual(aro[1].substring, concrete.1) + + XCTAssertEqual(aro["fieldB"]!.substring, concrete.2) + XCTAssertEqual(aro["fieldB"]!.substring, concrete.fieldB) + XCTAssertEqual(aro[2].substring, concrete.2) +} +private func checkSame( + _ aro: Regex, + _ concrete: Regex<(Substring, fieldA: Substring, fieldB: Substring)> +) { + XCTAssertEqual( + aro.contains(captureNamed: "fieldA"), + concrete.contains(captureNamed: "fieldA")) + XCTAssertEqual( + aro.contains(captureNamed: "fieldB"), + concrete.contains(captureNamed: "fieldB")) + XCTAssertEqual( + aro.contains(captureNamed: "notAField"), + concrete.contains(captureNamed: "notAField")) +} + +extension RegexTests { + func testAnyRegexOutput() { + let regex = try! Regex(#""" + (?x) + (? [^,]*) + , + (? [^,]*) + """#) + + let match = "abc,def".wholeMatch(of: regex)! + XCTAssertEqual(match.0, "abc,def") + XCTAssertEqual(match[0].substring, "abc,def") + + XCTAssertEqual(match["fieldA"]!.substring, "abc") + XCTAssertEqual(match.output["fieldA"]!.substring, "abc") + XCTAssertEqual(match[1].substring, "abc") + + XCTAssertEqual(match["fieldB"]!.substring, "def") + XCTAssertEqual(match.output["fieldB"]!.substring, "def") + XCTAssertEqual(match[2].substring, "def") + + XCTAssertNil(match["notACapture"]) + XCTAssertNil(match.output["notACapture"]) + XCTAssertEqual(match.count, 3) + + XCTAssert(regex.contains(captureNamed: "fieldA")) + XCTAssert(regex.contains(captureNamed: "fieldB")) + XCTAssertFalse(regex.contains(captureNamed: "notAField")) + + // MARK: Check equivalence with concrete + + let regexConcrete: + Regex<(Substring, fieldA: Substring, fieldB: Substring)> + = try! Regex(#""" + (?x) + (? [^,]*) + , + (? [^,]*) + """#) + checkSame(regex, regexConcrete) + + let matchConcrete = "abc,def".wholeMatch(of: regexConcrete)! + checkSame(match, matchConcrete) + + let output = match.output + let concreteOutput = matchConcrete.output + checkSame(output, concreteOutput) + + // TODO: ARO init from concrete match tuple + + let concreteOutputCasted = output.as( + (Substring, fieldA: Substring, fieldB: Substring).self + )! + checkSame(output, concreteOutputCasted) + + var concreteOutputCopy = concreteOutput + concreteOutputCopy = output.as()! + checkSame(output, concreteOutputCopy) + + // TODO: Regex.Match: init from tuple match and as to tuple match + + // TODO: Regex: init from tuple regex and as cast to tuple regex + + } + + func testDynamicCaptures() throws { + do { + let regex = try Regex("aabcc.") + let line = "aabccd" + let match = try XCTUnwrap(line.wholeMatch(of: regex)) + XCTAssertEqual(match.0, line[...]) + let output = match.output + XCTAssertEqual(output[0].substring, line[...]) + } + do { + let regex = try Regex( + #""" + (?[0-9A-F]+)(?:\.\.(?[0-9A-F]+))?\s+;\s+(?\w+).* + """#) + let line = """ + A6F0..A6F1 ; Extend # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM \ + COMBINING MARK TUKWENTIS + """ + let match = try XCTUnwrap(line.wholeMatch(of: regex)) + XCTAssertEqual(match.0, line[...]) + 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, lower: Substring, upper: Substring?, Substring).self)) + XCTAssertEqual(typedOutput.0, line[...]) + XCTAssertTrue(typedOutput.lower == "A6F0") + XCTAssertTrue(typedOutput.upper == "A6F1") + XCTAssertTrue(typedOutput.3 == "Extend") + } + } +} 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/CompileTests.swift b/Tests/RegexTests/CompileTests.swift index bc545d02e..eab46dca0 100644 --- a/Tests/RegexTests/CompileTests.swift +++ b/Tests/RegexTests/CompileTests.swift @@ -9,7 +9,6 @@ // //===----------------------------------------------------------------------===// - @testable import _RegexParser @testable import _StringProcessing diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index 67412d262..2c6b858cc 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) @@ -688,6 +693,14 @@ extension RegexTests { firstMatchTest(#"\p{gc=L}"#, input: "123abcXYZ", match: "a") firstMatchTest(#"\p{Lu}"#, input: "123abcXYZ", match: "X") + // U+0374 GREEK NUMERAL SIGN (Lm) + // U+00AA FEMININE ORDINAL INDICATOR (Lo) + firstMatchTest(#"\p{L}"#, input: "\u{0374}\u{00AA}123abcXYZ", match: "\u{0374}") + firstMatchTest(#"\p{Lc}"#, input: "\u{0374}\u{00AA}123abcXYZ", match: "a") + firstMatchTest(#"\p{Lc}"#, input: "\u{0374}\u{00AA}123XYZ", match: "X") + firstMatchTest(#"\p{L&}"#, input: "\u{0374}\u{00AA}123abcXYZ", match: "a") + firstMatchTest(#"\p{L&}"#, input: "\u{0374}\u{00AA}123XYZ", match: "X") + firstMatchTest( #"\P{Cc}"#, input: "\n\n\nXYZ", match: "X") firstMatchTest( @@ -869,15 +882,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( @@ -1197,6 +1210,102 @@ extension RegexTests { ("cafe", true), ("CaFe", true), ("EfAc", true)) + matchTest( + #"(?i)[a-f]{4}"#, + ("cafe", true), + ("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") + + firstMatchTest("(?xx)[ a && ab ]+", input: " aaba ", match: "aa") + firstMatchTest("(?xx)[ ] a ]+", input: " a]]a ] ", match: "a]]a") + } + + 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(#"^\d+"#))) + XCTAssertEqual(string.ranges(of: try Regex(#"^\d+"#)).count, 1) + XCTAssertEqual(string.ranges(of: try Regex(#"(?m)^\d+"#)).count, 5) + + let regex = try Regex(#"^\d+: [\w ]+$"#) + XCTAssertFalse(string.contains(regex)) + let allRanges = string.ranges(of: regex.anchorsMatchLineEndings()) + XCTAssertEqual(allRanges.count, 5) } func testMatchingOptionsScope() { @@ -1218,6 +1327,27 @@ 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 { + let regex = try Regex("c.f.") + XCTAssertTrue ("cafe".contains(regex)) + XCTAssertFalse("CaFe".contains(regex)) + + let caseInsensitiveRegex = regex.ignoresCase() + XCTAssertTrue("cafe".contains(caseInsensitiveRegex)) + XCTAssertTrue("CaFe".contains(caseInsensitiveRegex)) } // MARK: Character Semantics @@ -1390,13 +1520,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( @@ -1429,5 +1557,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 + } diff --git a/Tests/RegexTests/ParseTests.swift b/Tests/RegexTests/ParseTests.swift index c6ff3e46d..f0013b158 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 @@ -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) @@ -281,24 +284,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 { @@ -310,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( @@ -336,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))) @@ -357,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())) @@ -460,9 +457,22 @@ 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)[ ]]", 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. @@ -474,6 +484,41 @@ 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("[:a]", charClass(":", "a")) + parseTest("[a:]", charClass("a", ":")) + 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(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( @@ -502,6 +547,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)) ))) @@ -590,6 +641,15 @@ extension RegexTests { parseTest( "~~*", concat("~", zeroOrMore(of: "~"))) + parseTest( + "[ && ]", + charClass(.setOperation([" "], .init(faking: .intersection), [" ", " "])) + ) + parseTest("(?x)[ a && b ]", concat( + changeMatchingOptions(matchingOptions(adding: .extended)), + charClass(.setOperation(["a"], .init(faking: .intersection), ["b"])) + )) + // MARK: Quotes parseTest( @@ -705,32 +765,32 @@ extension RegexTests { parseTest( #"a(?