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 RIGHT_CURLY_SEMICOLON_OR_RIGHT_PAREN: KindSet =
44 KindSet::new(&[Kind::RightCurly, Kind::Semicolon, Kind::RightParen]);
45
46 pub const LEFT_CURLY_OR_SEMICOLON: KindSet = KindSet::new(&[Kind::LeftCurly, Kind::Semicolon]);
49
50 pub const LEFT_CURLY_RIGHT_PAREN_OR_SEMICOLON: KindSet =
53 KindSet::new(&[Kind::LeftCurly, Kind::RightParen, Kind::Semicolon]);
54
55 pub const LEFT_CURLY_RIGHT_PAREN_COMMA_OR_SEMICOLON: KindSet =
58 KindSet::new(&[Kind::LeftCurly, Kind::RightParen, Kind::Comma, Kind::Semicolon]);
59
60 pub const IDENT_LIKE: KindSet = KindSet::new(&[Kind::Ident, Kind::AtKeyword, Kind::Function, Kind::Hash]);
62
63 pub const ATOM_LIKE: KindSet = KindSet::new(&[Kind::Ident, Kind::Function, Kind::AtKeyword, Kind::Dimension]);
67
68 pub const NAMED: KindSet = KindSet::new(&[
71 Kind::Ident,
72 Kind::Function,
73 Kind::AtKeyword,
74 Kind::Hash,
75 Kind::String,
76 Kind::Url,
77 Kind::Comment,
78 Kind::UnicodeRange,
79 Kind::Dimension,
80 Kind::BadIdent,
81 Kind::BadFunction,
82 Kind::BadAtKeyword,
83 Kind::BadHash,
84 Kind::BadString,
85 Kind::BadUrl,
86 Kind::BadComment,
87 Kind::BadDimension,
88 ]);
89
90 pub const DELIM_LIKE: KindSet = KindSet::new(&[
92 Kind::Delim,
93 Kind::Colon,
94 Kind::Semicolon,
95 Kind::Comma,
96 Kind::LeftSquare,
97 Kind::RightSquare,
98 Kind::LeftParen,
99 Kind::RightParen,
100 Kind::LeftCurly,
101 Kind::RightCurly,
102 ]);
103
104 pub const PAIRWISE_START: KindSet = KindSet::new(&[Kind::LeftCurly, Kind::LeftParen, Kind::LeftSquare]);
106 pub const PAIRWISE_END: KindSet = KindSet::new(&[Kind::RightCurly, Kind::RightParen, Kind::RightSquare]);
109
110 pub const ANY: KindSet = KindSet(u64::MAX);
112
113 pub const fn new(kinds: &[Kind]) -> Self {
117 let mut u = 0;
118 let mut i = 0;
119 let len = kinds.len();
120 while i < len {
121 u |= 1 << (kinds[i] as u8 & 0b111111);
122 i += 1;
123 }
124 Self(u)
125 }
126
127 pub const fn add(&self, kind: Kind) -> Self {
131 Self(self.0 | (1 << (kind as u8 & 0b111111)))
132 }
133
134 pub const fn combine(&self, ks: KindSet) -> Self {
138 Self(self.0 | ks.0)
139 }
140
141 pub const fn remove(&self, kind: Kind) -> Self {
145 Self(self.0 ^ (1 << (kind as u8 & 0b111111)))
146 }
147
148 pub const fn contains(&self, kind: Kind) -> bool {
150 self.0 & (1 << (kind as u8 & 0b111111)) != 0
151 }
152
153 pub(crate) const fn contains_bits(&self, kind_bits: u8) -> bool {
154 self.0 & (1 << (kind_bits & 0b111111)) != 0
155 }
156}
157
158#[test]
159fn test_kindset_contains() {
160 let set = KindSet::new(&[Kind::Eof, Kind::Whitespace, Kind::Comment]);
161 assert!(set.contains(Kind::Eof));
162 assert!(set.contains(Kind::Whitespace));
163 assert!(set.contains(Kind::Comment));
164 assert!(!set.contains(Kind::String));
165 assert!(!set.contains(Kind::Url));
166
167 let set = KindSet::new(&[Kind::LeftCurly, Kind::LeftSquare, Kind::LeftParen]);
168
169 assert!(set.contains(Kind::LeftCurly));
170 assert!(!set.contains(Kind::RightCurly));
171 assert!(set.contains(Kind::LeftSquare));
172 assert!(!set.contains(Kind::RightSquare));
173 assert!(set.contains(Kind::LeftParen));
174 assert!(!set.contains(Kind::RightParen));
175 assert!(!set.contains(Kind::Ident));
176
177 assert!(KindSet::COMMENTS.contains(Kind::Comment));
178 assert!(!KindSet::COMMENTS.contains(Kind::Delim));
179}
180
181#[test]
182fn test_kindset_add_remove() {
183 let k_ident = KindSet::new(&[Kind::Ident]);
184 let k_ident_eof = k_ident.add(Kind::Eof);
185 assert!(k_ident.contains(Kind::Ident));
186 assert!(k_ident_eof.contains(Kind::Ident));
187 assert!(k_ident_eof.contains(Kind::Eof));
188 assert!(!k_ident_eof.remove(Kind::Eof).contains(Kind::Eof));
189}