// Unicode General Category (UAX #44).
//
// The 30 standard categories grouped by major class. The `Category` type is
// a closed union — exhaustive `match` is compile-checked; a new Unicode
// version that adds a category is a semver-significant breaking change
// (by design; see design/candidate-v3.md §10 improvement 3).
//
// Each category primitive's `code()` method returns its two-letter
// identifier (e.g., `"Lu"`, `"Mn"`). Categories implement `Stringable`
// so `.string()` returns the same.
// Letter
primitive Lu // Uppercase Letter
fun code(): String val => "Lu"
fun string(): String val => "Lu"
primitive Ll // Lowercase Letter
fun code(): String val => "Ll"
fun string(): String val => "Ll"
primitive Lt // Titlecase Letter
fun code(): String val => "Lt"
fun string(): String val => "Lt"
primitive Lm // Modifier Letter
fun code(): String val => "Lm"
fun string(): String val => "Lm"
primitive Lo // Other Letter
fun code(): String val => "Lo"
fun string(): String val => "Lo"
// Mark
primitive Mn // Nonspacing Mark
fun code(): String val => "Mn"
fun string(): String val => "Mn"
primitive Mc // Spacing Mark
fun code(): String val => "Mc"
fun string(): String val => "Mc"
primitive Me // Enclosing Mark
fun code(): String val => "Me"
fun string(): String val => "Me"
// Number
primitive Nd // Decimal Number
fun code(): String val => "Nd"
fun string(): String val => "Nd"
primitive Nl // Letter Number
fun code(): String val => "Nl"
fun string(): String val => "Nl"
primitive No // Other Number
fun code(): String val => "No"
fun string(): String val => "No"
// Punctuation
primitive Pc // Connector Punctuation
fun code(): String val => "Pc"
fun string(): String val => "Pc"
primitive Pd // Dash Punctuation
fun code(): String val => "Pd"
fun string(): String val => "Pd"
primitive Ps // Open Punctuation
fun code(): String val => "Ps"
fun string(): String val => "Ps"
primitive Pe // Close Punctuation
fun code(): String val => "Pe"
fun string(): String val => "Pe"
primitive Pi // Initial Punctuation
fun code(): String val => "Pi"
fun string(): String val => "Pi"
primitive Pf // Final Punctuation
fun code(): String val => "Pf"
fun string(): String val => "Pf"
primitive Po // Other Punctuation
fun code(): String val => "Po"
fun string(): String val => "Po"
// Symbol
primitive Sm // Math Symbol
fun code(): String val => "Sm"
fun string(): String val => "Sm"
primitive Sc // Currency Symbol
fun code(): String val => "Sc"
fun string(): String val => "Sc"
primitive Sk // Modifier Symbol
fun code(): String val => "Sk"
fun string(): String val => "Sk"
primitive So // Other Symbol
fun code(): String val => "So"
fun string(): String val => "So"
// Separator
primitive Zs // Space Separator
fun code(): String val => "Zs"
fun string(): String val => "Zs"
primitive Zl // Line Separator
fun code(): String val => "Zl"
fun string(): String val => "Zl"
primitive Zp // Paragraph Separator
fun code(): String val => "Zp"
fun string(): String val => "Zp"
// Other
primitive Cc // Control
fun code(): String val => "Cc"
fun string(): String val => "Cc"
primitive Cf // Format
fun code(): String val => "Cf"
fun string(): String val => "Cf"
primitive Cs // Surrogate
fun code(): String val => "Cs"
fun string(): String val => "Cs"
primitive Co // Private Use
fun code(): String val => "Co"
fun string(): String val => "Co"
primitive Cn // Unassigned (also used for "I don't know")
fun code(): String val => "Cn"
fun string(): String val => "Cn"
type Category is
( Lu | Ll | Lt | Lm | Lo
| Mn | Mc | Me
| Nd | Nl | No
| Pc | Pd | Ps | Pe | Pi | Pf | Po
| Sm | Sc | Sk | So
| Zs | Zl | Zp
| Cc | Cf | Cs | Co | Cn
)
primitive Categories
"""
Operations on the Category union. The `_all` array is generated by
`unicode-build` alongside the rest of the closed-union enumeration
arrays — tests can iterate all 30 variants without hand-maintaining
the list (see design/candidate-v3.md Adj-23).
"""
fun from_iso(s: String box): (Category | None) =>
"""
Look up a category by its two-letter ISO identifier (case-sensitive).
Returns `None` for unrecognized input. Total over its input.
"""
match s
| "Lu" => Lu | "Ll" => Ll | "Lt" => Lt | "Lm" => Lm | "Lo" => Lo
| "Mn" => Mn | "Mc" => Mc | "Me" => Me
| "Nd" => Nd | "Nl" => Nl | "No" => No
| "Pc" => Pc | "Pd" => Pd | "Ps" => Ps | "Pe" => Pe
| "Pi" => Pi | "Pf" => Pf | "Po" => Po
| "Sm" => Sm | "Sc" => Sc | "Sk" => Sk | "So" => So
| "Zs" => Zs | "Zl" => Zl | "Zp" => Zp
| "Cc" => Cc | "Cf" => Cf | "Cs" => Cs | "Co" => Co | "Cn" => Cn
else
None
end
fun _to_byte(c: Category): U8 =>
"""
Stable byte encoding for the 30 Category variants. Used by
`unicode-build` and by the generated lookup tables to keep the
encoding compact (one byte per codepoint range entry). The exact
mapping is an implementation detail — callers should never see
these bytes directly.
"""
match c
| Lu => 0 | Ll => 1 | Lt => 2 | Lm => 3 | Lo => 4
| Mn => 5 | Mc => 6 | Me => 7
| Nd => 8 | Nl => 9 | No => 10
| Pc => 11 | Pd => 12 | Ps => 13 | Pe => 14
| Pi => 15 | Pf => 16 | Po => 17
| Sm => 18 | Sc => 19 | Sk => 20 | So => 21
| Zs => 22 | Zl => 23 | Zp => 24
| Cc => 25 | Cf => 26 | Cs => 27 | Co => 28 | Cn => 29
end
fun _from_byte(b: U8): Category =>
"""
Inverse of `_to_byte`. Unknown bytes return `Cn` (Unassigned) — this
is also the failure case for malformed generated tables, which would
indicate a codegen / runtime version mismatch.
"""
match b
| 0 => Lu | 1 => Ll | 2 => Lt | 3 => Lm | 4 => Lo
| 5 => Mn | 6 => Mc | 7 => Me
| 8 => Nd | 9 => Nl | 10 => No
| 11 => Pc | 12 => Pd | 13 => Ps | 14 => Pe
| 15 => Pi | 16 => Pf | 17 => Po
| 18 => Sm | 19 => Sc | 20 => Sk | 21 => So
| 22 => Zs | 23 => Zl | 24 => Zp
| 25 => Cc | 26 => Cf | 27 => Cs | 28 => Co | 29 => Cn
else
Cn
end