1use crate::Kind;
2
3#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct KindSet(u64);
18
19impl KindSet {
20 pub const NONE: KindSet = KindSet::new(&[]);
22
23 pub const TRIVIA: KindSet = KindSet::new(&[Kind::Whitespace, Kind::Comment]);
25
26 pub const WHITESPACE: KindSet = KindSet::new(&[Kind::Whitespace]);
29
30 pub const COMMENTS: KindSet = KindSet::new(&[Kind::Comment]);
33
34 pub const WHITESPACE_OR_SEMICOLON: KindSet = KindSet::new(&[Kind::Whitespace, Kind::Semicolon]);
36
37 pub const RIGHT_CURLY_OR_SEMICOLON: KindSet = KindSet::new(&[Kind::RightCurly, Kind::Semicolon]);
40
41 pub const LEFT_CURLY_OR_SEMICOLON: KindSet = KindSet::new(&[Kind::LeftCurly, Kind::Semicolon]);
44
45 pub const LEFT_CURLY_RIGHT_PAREN_OR_SEMICOLON: KindSet =
48 KindSet::new(&[Kind::LeftCurly, Kind::RightParen, Kind::Semicolon]);
49
50 pub const LEFT_CURLY_RIGHT_PAREN_COMMA_OR_SEMICOLON: KindSet =
53 KindSet::new(&[Kind::LeftCurly, Kind::RightParen, Kind::Comma, Kind::Semicolon]);
54
55 pub const IDENT_LIKE: KindSet = KindSet::new(&[Kind::Ident, Kind::AtKeyword, Kind::Function, Kind::Hash]);
57
58 pub const ATOM_LIKE: KindSet = KindSet::new(&[Kind::Ident, Kind::Function, Kind::AtKeyword, Kind::Dimension]);
62
63 pub const DELIM_LIKE: KindSet = KindSet::new(&[
65 Kind::Delim,
66 Kind::Colon,
67 Kind::Semicolon,
68 Kind::Comma,
69 Kind::LeftSquare,
70 Kind::RightSquare,
71 Kind::LeftParen,
72 Kind::RightParen,
73 Kind::LeftCurly,
74 Kind::RightCurly,
75 ]);
76
77 pub const PAIRWISE_START: KindSet = KindSet::new(&[Kind::LeftCurly, Kind::LeftParen, Kind::LeftSquare]);
79 pub const PAIRWISE_END: KindSet = KindSet::new(&[Kind::RightCurly, Kind::RightParen, Kind::RightSquare]);
82
83 pub const ANY: KindSet = KindSet(u64::MAX);
85
86 pub const fn new(kinds: &[Kind]) -> Self {
90 let mut u = 0;
91 let mut i = 0;
92 let len = kinds.len();
93 while i < len {
94 u |= 1 << (kinds[i] as u8 & 0b111111);
95 i += 1;
96 }
97 Self(u)
98 }
99
100 pub const fn add(&self, kind: Kind) -> Self {
104 Self(self.0 | (1 << (kind as u8 & 0b111111)))
105 }
106
107 pub const fn combine(&self, ks: KindSet) -> Self {
111 Self(self.0 | ks.0)
112 }
113
114 pub const fn remove(&self, kind: Kind) -> Self {
118 Self(self.0 ^ (1 << (kind as u8 & 0b111111)))
119 }
120
121 pub fn contains(&self, kind: Kind) -> bool {
123 self.0 & (1 << (kind as u8 & 0b111111)) != 0
124 }
125
126 pub(crate) const fn contains_bits(&self, kind_bits: u8) -> bool {
127 self.0 & (1 << (kind_bits & 0b111111)) != 0
128 }
129}
130
131#[test]
132fn test_kindset_contains() {
133 let set = KindSet::new(&[Kind::Eof, Kind::Whitespace, Kind::Comment]);
134 assert!(set.contains(Kind::Eof));
135 assert!(set.contains(Kind::Whitespace));
136 assert!(set.contains(Kind::Comment));
137 assert!(!set.contains(Kind::String));
138 assert!(!set.contains(Kind::Url));
139
140 let set = KindSet::new(&[Kind::LeftCurly, Kind::LeftSquare, Kind::LeftParen]);
141
142 assert!(set.contains(Kind::LeftCurly));
143 assert!(!set.contains(Kind::RightCurly));
144 assert!(set.contains(Kind::LeftSquare));
145 assert!(!set.contains(Kind::RightSquare));
146 assert!(set.contains(Kind::LeftParen));
147 assert!(!set.contains(Kind::RightParen));
148 assert!(!set.contains(Kind::Ident));
149
150 assert!(KindSet::COMMENTS.contains(Kind::Comment));
151 assert!(!KindSet::COMMENTS.contains(Kind::Delim));
152}
153
154#[test]
155fn test_kindset_add_remove() {
156 let k_ident = KindSet::new(&[Kind::Ident]);
157 let k_ident_eof = k_ident.add(Kind::Eof);
158 assert!(k_ident.contains(Kind::Ident));
159 assert!(k_ident_eof.contains(Kind::Ident));
160 assert!(k_ident_eof.contains(Kind::Eof));
161 assert!(!k_ident_eof.remove(Kind::Eof).contains(Kind::Eof));
162}