Repository: Eliah-Lakhin/lady-deirdre (language: rust)

Issue:
derive(Token)-generated code results in "non-exhaustive patterns:
Trying to match even just a single unicode character results in generated Rust code that fails to compile (match exhaustiveness check)

```rust
#[derive(Clone, Copy, PartialEq, Eq, Debug, Token)]
#[repr(u8)]
pub enum MyToken {
    EOI = 0,
    Mismatch = 1,
    #[rule('\u{2260}')]
    Ne,
}
```

Error:
```
139 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Token)]
    |                                             ^^^^^ patterns `'\0'..='≟'`, `'≡'..='\u{d7ff}'` and `'\u{e000}'..='\u{10ffff}'` not covered
```

Cargo.toml
```rust
[dependencies]
lady-deirdre = "2.0.0"
lady-deirdre-derive = "2.0.0"
```

<details>
<summary><code>#[dump]</code> output</summary>

```rust
impl ::lady_deirdre::lexis::Token for MyToken {
     const LOOKBACK: ::lady_deirdre::lexis::Length = 1;
     fn scan(session: &mut impl ::lady_deirdre::lexis::LexisSession) -> Self {
         #[allow(unused_mut)]
         let mut state = 1usize;
         #[allow(unused_mut)]
         let mut token = Self::Mismatch;
         loop {
             let byte = ::lady_deirdre::lexis::LexisSession::advance(session);
             if byte == 0xFF {
                 break;
             }
             match state {
                 1usize => {
                     let ch = unsafe {
                         ::lady_deirdre::lexis::LexisSession::read(session)
                     };
                     match ch {
                         '≠' => {
                             unsafe {
                                 ::lady_deirdre::lexis::LexisSession::submit(session)
                             };
                             token = Self::Ne;
                             break;
                         }
                     }
                     break;
                 }
                 #[cfg(not(debug_assertions))]
                 _ => {}
                 #[cfg(debug_assertions)]
                 state => ::std::panic!("Invalid state {state}."),
             }
         }
         token
     }
     #[inline(always)]
     fn eoi() -> Self {
         Self::EOI
     }
     #[inline(always)]
     fn mismatch() -> Self {
         Self::Mismatch
     }
     #[inline(always)]
     fn rule(self) -> ::lady_deirdre::lexis::TokenRule {
         self as u8
     }
     fn rule_name(
         rule: ::lady_deirdre::lexis::TokenRule,
     ) -> ::std::option::Option<&'static str> {
         if Self::EOI as u8 == rule {
             return ::std::option::Option::Some("EOI");
         }
         if Self::Mismatch as u8 == rule {
             return ::std::option::Option::Some("Mismatch");
         }
         if Self::Ne as u8 == rule {
             return ::std::option::Option::Some("Ne");
         }
         None
     }
     #[allow(unused_variables)]
     fn rule_description(
         rule: ::lady_deirdre::lexis::TokenRule,
         verbose: bool,
     ) -> ::std::option::Option<&'static str> {
         if Self::EOI as u8 == rule {
             return ::std::option::Option::Some("<eoi>");
         }
         if Self::Mismatch as u8 == rule {
             return ::std::option::Option::Some("<mismatch>");
         }
         if Self::Ne as u8 == rule {
             return ::std::option::Option::Some("≠");
         }
         None
     }
 }
```

</details>

I did not find a workaround. For now, I will have to drop Unicode support for my language.


Discussion / hints:
@chklauser Thank you for the report. The bug confirmed, and I'm working on a fix.

Fix patch:
diff --git a/work/crates/derive/src/token/output.rs b/work/crates/derive/src/token/output.rs
index fe05c50..a932b26 100644
--- a/work/crates/derive/src/token/output.rs
+++ b/work/crates/derive/src/token/output.rs
@@ -221,9 +221,12 @@ impl<'a> Output<'a> {
 
         if !unicode_cases.is_empty() {
             statements.push_branching(quote!(
-                match ch {#(
-                    #unicode_cases,
-                )*}
+                match ch {
+                    #(
+                        #unicode_cases
+                    )*
+                    _ => (),
+                }
             ))
         }
 


Test patch: