Skip to main content

ktrs_parser/
token_set.rs

1//! IntelliJ `TokenSet`: an immutable, const-constructible bit set of [`SyntaxKind`]s.
2
3use ktrs_syntax::SyntaxKind;
4
5const WORDS: usize = 8;
6const _: () = assert!((SyntaxKind::DUMMY_HOLDER as usize) < WORDS * 64, "grow TokenSet::WORDS");
7
8#[derive(Clone, Copy, PartialEq, Eq, Hash)]
9pub struct TokenSet([u64; WORDS]);
10
11impl TokenSet {
12    pub const EMPTY: TokenSet = TokenSet([0; WORDS]);
13
14    /// `TokenSet.create(...)`.
15    pub const fn create(kinds: &[SyntaxKind]) -> TokenSet {
16        let mut bits = [0u64; WORDS];
17        let mut i = 0;
18        while i < kinds.len() {
19            let k = kinds[i] as usize;
20            bits[k / 64] |= 1 << (k % 64);
21            i += 1;
22        }
23        TokenSet(bits)
24    }
25
26    /// `TokenSet.orSet(...)`.
27    pub const fn or_set(sets: &[TokenSet]) -> TokenSet {
28        let mut bits = [0u64; WORDS];
29        let mut s = 0;
30        while s < sets.len() {
31            let mut w = 0;
32            while w < WORDS {
33                bits[w] |= sets[s].0[w];
34                w += 1;
35            }
36            s += 1;
37        }
38        TokenSet(bits)
39    }
40
41    /// `TokenSet.andSet(a, b)`.
42    pub const fn and_set(a: TokenSet, b: TokenSet) -> TokenSet {
43        let mut bits = [0u64; WORDS];
44        let mut w = 0;
45        while w < WORDS {
46            bits[w] = a.0[w] & b.0[w];
47            w += 1;
48        }
49        TokenSet(bits)
50    }
51
52    /// `TokenSet.andNot(a, b)`.
53    pub const fn and_not(a: TokenSet, b: TokenSet) -> TokenSet {
54        let mut bits = [0u64; WORDS];
55        let mut w = 0;
56        while w < WORDS {
57            bits[w] = a.0[w] & !b.0[w];
58            w += 1;
59        }
60        TokenSet(bits)
61    }
62
63    /// Accepts `SyntaxKind` or `Option<SyntaxKind>`; like Java, `contains(null)` is false.
64    pub fn contains(self, kind: impl Into<Option<SyntaxKind>>) -> bool {
65        match kind.into() {
66            Some(k) => self.0[k as usize / 64] & (1 << (k as usize % 64)) != 0,
67            None => false,
68        }
69    }
70
71    pub fn intersects(self, other: TokenSet) -> bool {
72        self.0.iter().zip(other.0).any(|(a, b)| a & b != 0)
73    }
74
75    pub fn types(self) -> impl Iterator<Item = SyntaxKind> {
76        (0..WORDS * 64)
77            .filter(move |&i| self.0[i / 64] & (1 << (i % 64)) != 0)
78            .map(|i| SyntaxKind::from_raw(i as u16))
79    }
80}
81
82impl std::fmt::Debug for TokenSet {
83    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        f.debug_set().entries(self.types()).finish()
85    }
86}