Skip to main content

openpql_range_parser/ast/
list.rs

1use super::{Error, LalrError, Loc, RangeCard, RankConst, SuitConst, ToString};
2
3/// Element of a bracketed card list.
4#[derive(Copy, Clone, PartialEq, Eq, Debug, derive_more::Display)]
5pub enum ListElem {
6    /// Concrete rank and concrete suit.
7    #[display("{_0}{_1}")]
8    CC(RankConst, SuitConst),
9    /// Concrete rank with any suit.
10    #[display("{_0}")]
11    CA(RankConst),
12    /// Any rank with concrete suit.
13    #[display("{_0}")]
14    AC(SuitConst),
15}
16
17fn to_str(elems: &[ListElem]) -> String {
18    format!(
19        "[{}]",
20        elems
21            .iter()
22            .map(ToString::to_string)
23            .collect::<Vec<_>>()
24            .join(",")
25    )
26}
27
28/// Bracketed list of simple cards.
29#[derive(Clone, PartialEq, Eq, Debug, derive_more::From, derive_more::Display)]
30#[display("{}", to_str(_0))]
31pub struct List(pub Vec<ListElem>);
32
33impl TryFrom<(Loc, Vec<RangeCard>, Loc)> for List {
34    type Error = LalrError<'static>;
35
36    fn try_from((l, v, r): (Loc, Vec<RangeCard>, Loc)) -> Result<Self, Self::Error> {
37        let mut inner = vec![];
38
39        for c in v {
40            match c {
41                RangeCard::CC(r, s) => {
42                    inner.push(ListElem::CC(r, s));
43                }
44                RangeCard::CA(r) => {
45                    inner.push(ListElem::CA(r));
46                }
47                RangeCard::AC(s) => {
48                    inner.push(ListElem::AC(s));
49                }
50                _ => {
51                    return Err(Error::InvalidList((l, r)).into());
52                }
53            }
54        }
55
56        Ok(Self(inner))
57    }
58}
59
60#[cfg(test)]
61#[cfg_attr(coverage_nightly, coverage(off))]
62mod tests {
63    use super::*;
64    use crate::*;
65
66    fn assert_list(src: &str, expected: &str) {
67        let list = parse_list(src).unwrap();
68
69        assert_eq!(list.to_string(), expected, "{src} != {expected}");
70    }
71
72    #[quickcheck]
73    fn test_list(c: RangeCard) {
74        let src = format!("[{c}]");
75        let res = parse_list(&src);
76
77        let is_err = match c {
78            RangeCard::CC(_, _) | RangeCard::CA(_) | RangeCard::AC(_) => false,
79            RangeCard::CV(_, _)
80            | RangeCard::VC(_, _)
81            | RangeCard::VV(_, _)
82            | RangeCard::VA(_)
83            | RangeCard::AV(_)
84            | RangeCard::AA => true,
85        };
86
87        if is_err {
88            assert_eq!(res, Err(Error::InvalidList((0, src.len())).into()));
89        } else {
90            assert_eq!(res, Ok((0, vec![c], 0).try_into().unwrap()));
91        }
92    }
93
94    #[test]
95    fn test_list_ok() {
96        assert_list("[A, s]", "[A,s]");
97    }
98
99    #[test]
100    fn test_list_error() {
101        assert_eq!(parse_list("[B] "), Err(Error::InvalidList((0, 3)).into()));
102        assert_eq!(parse_list("[Bs]"), Err(Error::InvalidList((0, 4)).into()));
103        assert_eq!(parse_list("[*w]"), Err(Error::InvalidList((0, 4)).into()));
104        assert_eq!(parse_list("[Aw]"), Err(Error::InvalidList((0, 4)).into()));
105        assert_eq!(parse_list("[Bw]"), Err(Error::InvalidList((0, 4)).into()));
106        assert_eq!(parse_list("[*] "), Err(Error::InvalidList((0, 3)).into()));
107    }
108}