Skip to main content

openpql_range_parser/ast/
rank.rs

1use super::{Display, Error, LocInfo, ResultE};
2
3pub type RankConst = openpql_prelude::Rank;
4
5/// Single-letter rank variable token.
6#[derive(Copy, Clone, PartialEq, Eq, Debug, Display)]
7pub enum RankVar {
8    /// Rank variable "B".
9    #[display("B")]
10    RB,
11    /// Rank variable "E".
12    #[display("E")]
13    RE,
14    /// Rank variable "F".
15    #[display("F")]
16    RF,
17    /// Rank variable "G".
18    #[display("G")]
19    RG,
20    /// Rank variable "I".
21    #[display("I")]
22    RI,
23    /// Rank variable "L".
24    #[display("L")]
25    RL,
26    /// Rank variable "M".
27    #[display("M")]
28    RM,
29    /// Rank variable "N".
30    #[display("N")]
31    RN,
32    /// Rank variable "O".
33    #[display("O")]
34    RO,
35    /// Rank variable "P".
36    #[display("P")]
37    RP,
38    /// Rank variable "R".
39    #[display("R")]
40    RR,
41    /// Rank variable "U".
42    #[display("U")]
43    RU,
44    /// Rank variable "V".
45    #[display("V")]
46    RV,
47}
48
49/// Rank slot in a range card: concrete, variable, or wildcard.
50#[derive(Copy, Clone, PartialEq, Eq, Debug, Display)]
51pub enum CardRank {
52    /// Concrete rank.
53    #[display("{_0}")]
54    Const(RankConst),
55    /// Rank variable.
56    #[display("{_0}")]
57    Var(RankVar),
58    /// Wildcard `*` matching any rank.
59    #[display("*")]
60    Any,
61}
62
63impl CardRank {
64    pub(crate) fn from_token(
65        is_shortdeck: bool,
66        c: char,
67        loc: LocInfo,
68    ) -> ResultE<'static, Self> {
69        if is_shortdeck {
70            match c {
71                '2' | '3' | '4' | '5' => {
72                    return Err(Error::InvalidRank(loc).into());
73                }
74                _ => (),
75            }
76        }
77
78        match c {
79            '*' => Ok(Self::Any),
80
81            '2' => Ok(Self::Const(RankConst::R2)),
82            '3' => Ok(Self::Const(RankConst::R3)),
83            '4' => Ok(Self::Const(RankConst::R4)),
84            '5' => Ok(Self::Const(RankConst::R5)),
85            '6' => Ok(Self::Const(RankConst::R6)),
86            '7' => Ok(Self::Const(RankConst::R7)),
87            '8' => Ok(Self::Const(RankConst::R8)),
88            '9' => Ok(Self::Const(RankConst::R9)),
89
90            'T' | 't' => Ok(Self::Const(RankConst::RT)),
91            'J' | 'j' => Ok(Self::Const(RankConst::RJ)),
92            'Q' | 'q' => Ok(Self::Const(RankConst::RQ)),
93            'K' | 'k' => Ok(Self::Const(RankConst::RK)),
94            'A' | 'a' => Ok(Self::Const(RankConst::RA)),
95
96            'B' | 'b' => Ok(Self::Var(RankVar::RB)),
97            'E' | 'e' => Ok(Self::Var(RankVar::RE)),
98            'F' | 'f' => Ok(Self::Var(RankVar::RF)),
99            'G' | 'g' => Ok(Self::Var(RankVar::RG)),
100            'I' | 'i' => Ok(Self::Var(RankVar::RI)),
101            'L' | 'l' => Ok(Self::Var(RankVar::RL)),
102            'M' | 'm' => Ok(Self::Var(RankVar::RM)),
103            'N' | 'n' => Ok(Self::Var(RankVar::RN)),
104            'O' | 'o' => Ok(Self::Var(RankVar::RO)),
105            'P' | 'p' => Ok(Self::Var(RankVar::RP)),
106            'R' | 'r' => Ok(Self::Var(RankVar::RR)),
107            'U' | 'u' => Ok(Self::Var(RankVar::RU)),
108            'V' | 'v' => Ok(Self::Var(RankVar::RV)),
109
110            _ => Err(Error::InvalidRank(loc).into()),
111        }
112    }
113}
114
115#[cfg(test)]
116#[cfg_attr(coverage_nightly, coverage(off))]
117mod tests {
118    use super::*;
119    use crate::*;
120
121    impl Arbitrary for RankVar {
122        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
123            *g.choose(&[
124                Self::RB,
125                Self::RE,
126                Self::RF,
127                Self::RG,
128                Self::RI,
129                Self::RL,
130                Self::RM,
131                Self::RN,
132                Self::RO,
133                Self::RP,
134                Self::RR,
135                Self::RU,
136                Self::RV,
137            ])
138            .unwrap()
139        }
140    }
141
142    #[test]
143    fn test_card_rank_const() {
144        assert_range_card("2", "2");
145        assert_range_card("3", "3");
146        assert_range_card("4", "4");
147        assert_range_card("5", "5");
148        assert_range_card("6", "6");
149        assert_range_card("7", "7");
150        assert_range_card("8", "8");
151        assert_range_card("9", "9");
152
153        assert_range_card("T", "T");
154        assert_range_card("J", "J");
155        assert_range_card("Q", "Q");
156        assert_range_card("K", "K");
157        assert_range_card("A", "A");
158
159        assert_range_card("t", "T");
160        assert_range_card("j", "J");
161        assert_range_card("q", "Q");
162        assert_range_card("k", "K");
163        assert_range_card("a", "A");
164    }
165
166    #[test]
167    fn test_card_rank_var() {
168        assert_range_card("B", "B");
169        assert_range_card("E", "E");
170        assert_range_card("F", "F");
171        assert_range_card("G", "G");
172        assert_range_card("I", "I");
173        assert_range_card("L", "L");
174        assert_range_card("M", "M");
175        assert_range_card("N", "N");
176        assert_range_card("O", "O");
177        assert_range_card("P", "P");
178        assert_range_card("R", "R");
179        assert_range_card("U", "U");
180        assert_range_card("V", "V");
181    }
182
183    #[test]
184    fn test_card_rank_var_lower() {
185        assert_range_card("b", "B");
186        assert_range_card("e", "E");
187        assert_range_card("f", "F");
188        assert_range_card("g", "G");
189        assert_range_card("i", "I");
190        assert_range_card("l", "L");
191        assert_range_card("m", "M");
192        assert_range_card("n", "N");
193        assert_range_card("o", "O");
194        assert_range_card("p", "P");
195        assert_range_card("r", "R");
196        assert_range_card("u", "U");
197        assert_range_card("v", "V");
198    }
199
200    #[test]
201    fn test_from_token() {
202        // guaranteed unreachable by lexer
203        assert![CardRank::from_token(false, '?', (0, 1)).is_err()];
204    }
205}