Skip to main content

openpql_range_parser/ast/
rank.rs

1use super::{Error, LocInfo, ResultE};
2
3pub type RankConst = openpql_prelude::Rank;
4
5/// Single-letter rank variable token.
6#[derive(Copy, Clone, PartialEq, Eq, Debug, derive_more::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, derive_more::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(is_shortdeck: bool, c: char, loc: LocInfo) -> ResultE<'static, Self> {
65        if is_shortdeck {
66            match c {
67                '2' | '3' | '4' | '5' => {
68                    return Err(Error::InvalidRank(loc).into());
69                }
70                _ => (),
71            }
72        }
73
74        match c {
75            '*' => Ok(Self::Any),
76
77            '2' => Ok(Self::Const(RankConst::R2)),
78            '3' => Ok(Self::Const(RankConst::R3)),
79            '4' => Ok(Self::Const(RankConst::R4)),
80            '5' => Ok(Self::Const(RankConst::R5)),
81            '6' => Ok(Self::Const(RankConst::R6)),
82            '7' => Ok(Self::Const(RankConst::R7)),
83            '8' => Ok(Self::Const(RankConst::R8)),
84            '9' => Ok(Self::Const(RankConst::R9)),
85
86            'T' | 't' => Ok(Self::Const(RankConst::RT)),
87            'J' | 'j' => Ok(Self::Const(RankConst::RJ)),
88            'Q' | 'q' => Ok(Self::Const(RankConst::RQ)),
89            'K' | 'k' => Ok(Self::Const(RankConst::RK)),
90            'A' | 'a' => Ok(Self::Const(RankConst::RA)),
91
92            'B' | 'b' => Ok(Self::Var(RankVar::RB)),
93            'E' | 'e' => Ok(Self::Var(RankVar::RE)),
94            'F' | 'f' => Ok(Self::Var(RankVar::RF)),
95            'G' | 'g' => Ok(Self::Var(RankVar::RG)),
96            'I' | 'i' => Ok(Self::Var(RankVar::RI)),
97            'L' | 'l' => Ok(Self::Var(RankVar::RL)),
98            'M' | 'm' => Ok(Self::Var(RankVar::RM)),
99            'N' | 'n' => Ok(Self::Var(RankVar::RN)),
100            'O' | 'o' => Ok(Self::Var(RankVar::RO)),
101            'P' | 'p' => Ok(Self::Var(RankVar::RP)),
102            'R' | 'r' => Ok(Self::Var(RankVar::RR)),
103            'U' | 'u' => Ok(Self::Var(RankVar::RU)),
104            'V' | 'v' => Ok(Self::Var(RankVar::RV)),
105
106            _ => Err(Error::InvalidRank(loc).into()),
107        }
108    }
109}
110
111#[cfg(test)]
112#[cfg_attr(coverage_nightly, coverage(off))]
113mod tests {
114    use super::*;
115    use crate::*;
116
117    impl quickcheck::Arbitrary for RankVar {
118        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
119            *g.choose(&[
120                Self::RB,
121                Self::RE,
122                Self::RF,
123                Self::RG,
124                Self::RI,
125                Self::RL,
126                Self::RM,
127                Self::RN,
128                Self::RO,
129                Self::RP,
130                Self::RR,
131                Self::RU,
132                Self::RV,
133            ])
134            .unwrap()
135        }
136    }
137
138    #[test]
139    fn test_card_rank_const() {
140        assert_range_card("2", "2");
141        assert_range_card("3", "3");
142        assert_range_card("4", "4");
143        assert_range_card("5", "5");
144        assert_range_card("6", "6");
145        assert_range_card("7", "7");
146        assert_range_card("8", "8");
147        assert_range_card("9", "9");
148
149        assert_range_card("T", "T");
150        assert_range_card("J", "J");
151        assert_range_card("Q", "Q");
152        assert_range_card("K", "K");
153        assert_range_card("A", "A");
154
155        assert_range_card("t", "T");
156        assert_range_card("j", "J");
157        assert_range_card("q", "Q");
158        assert_range_card("k", "K");
159        assert_range_card("a", "A");
160    }
161
162    #[test]
163    fn test_card_rank_var() {
164        assert_range_card("B", "B");
165        assert_range_card("E", "E");
166        assert_range_card("F", "F");
167        assert_range_card("G", "G");
168        assert_range_card("I", "I");
169        assert_range_card("L", "L");
170        assert_range_card("M", "M");
171        assert_range_card("N", "N");
172        assert_range_card("O", "O");
173        assert_range_card("P", "P");
174        assert_range_card("R", "R");
175        assert_range_card("U", "U");
176        assert_range_card("V", "V");
177    }
178
179    #[test]
180    fn test_card_rank_var_lower() {
181        assert_range_card("b", "B");
182        assert_range_card("e", "E");
183        assert_range_card("f", "F");
184        assert_range_card("g", "G");
185        assert_range_card("i", "I");
186        assert_range_card("l", "L");
187        assert_range_card("m", "M");
188        assert_range_card("n", "N");
189        assert_range_card("o", "O");
190        assert_range_card("p", "P");
191        assert_range_card("r", "R");
192        assert_range_card("u", "U");
193        assert_range_card("v", "V");
194    }
195
196    #[test]
197    fn test_from_token() {
198        // guaranteed unreachable by lexer
199        assert![CardRank::from_token(false, '?', (0, 1)).is_err()];
200    }
201}