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(
30    Clone, PartialEq, Eq, Debug, derive_more::From, derive_more::Display,
31)]
32#[display("{}", to_str(_0))]
33pub struct List(pub Vec<ListElem>);
34
35impl TryFrom<(Loc, Vec<RangeCard>, Loc)> for List {
36    type Error = LalrError<'static>;
37
38    fn try_from(
39        (l, v, r): (Loc, Vec<RangeCard>, Loc),
40    ) -> Result<Self, Self::Error> {
41        let mut inner = vec![];
42
43        for c in v {
44            match c {
45                RangeCard::CC(r, s) => {
46                    inner.push(ListElem::CC(r, s));
47                }
48                RangeCard::CA(r) => {
49                    inner.push(ListElem::CA(r));
50                }
51                RangeCard::AC(s) => {
52                    inner.push(ListElem::AC(s));
53                }
54                _ => {
55                    return Err(Error::InvalidList((l, r)).into());
56                }
57            }
58        }
59
60        Ok(Self(inner))
61    }
62}
63
64#[cfg(test)]
65#[cfg_attr(coverage_nightly, coverage(off))]
66mod tests {
67    use super::*;
68    use crate::*;
69
70    fn assert_list(src: &str, expected: &str) {
71        let list = parse_list(src).unwrap();
72
73        assert_eq!(list.to_string(), expected, "{src} != {expected}");
74    }
75
76    #[quickcheck]
77    fn test_list(c: RangeCard) {
78        let src = format!("[{c}]");
79        let res = parse_list(&src);
80
81        let is_err = match c {
82            RangeCard::CC(_, _) | RangeCard::CA(_) | RangeCard::AC(_) => false,
83            RangeCard::CV(_, _)
84            | RangeCard::VC(_, _)
85            | RangeCard::VV(_, _)
86            | RangeCard::VA(_)
87            | RangeCard::AV(_)
88            | RangeCard::AA => true,
89        };
90
91        if is_err {
92            assert_eq!(res, Err(Error::InvalidList((0, src.len())).into()));
93        } else {
94            assert_eq!(res, Ok((0, vec![c], 0).try_into().unwrap()));
95        }
96    }
97
98    #[test]
99    fn test_list_ok() {
100        assert_list("[A, s]", "[A,s]");
101    }
102
103    #[test]
104    fn test_list_error() {
105        assert_eq!(parse_list("[B] "), Err(Error::InvalidList((0, 3)).into()));
106        assert_eq!(parse_list("[Bs]"), Err(Error::InvalidList((0, 4)).into()));
107        assert_eq!(parse_list("[*w]"), Err(Error::InvalidList((0, 4)).into()));
108        assert_eq!(parse_list("[Aw]"), Err(Error::InvalidList((0, 4)).into()));
109        assert_eq!(parse_list("[Bw]"), Err(Error::InvalidList((0, 4)).into()));
110        assert_eq!(parse_list("[*] "), Err(Error::InvalidList((0, 3)).into()));
111    }
112}