use crate::syntax::SyntaxKind;
use std::convert::TryFrom;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TokenSet(pub(crate) u64);
impl TokenSet {
pub const EMPTY: TokenSet = TokenSet(0);
pub const fn insert_end(self) -> Self {
Self(self.0 | TokenSet::end_to_bit())
}
pub const fn insert_token(self, kind: SyntaxKind) -> Self {
Self(self.0 | TokenSet::token_to_bit(kind))
}
pub const fn insert(self, kind: Option<SyntaxKind>) -> Self {
match kind {
Some(kind) => self.insert_token(kind),
None => self.insert_end(),
}
}
pub const fn contains(self, kind: Option<SyntaxKind>) -> bool {
let bit = match kind {
Some(kind) => TokenSet::token_to_bit(kind),
None => TokenSet::end_to_bit(),
};
self.0 & bit != 0
}
pub const fn intersection(self, rhs: Self) -> Self {
Self(self.0 & rhs.0)
}
pub const fn is_empty(self) -> bool {
self.0 == 0
}
pub const fn union(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
pub const fn iter(self) -> TokenSetIter {
TokenSetIter {
token_set: self,
bit_index: 0,
}
}
pub(crate) const fn end_to_bit() -> u64 {
1
}
pub(crate) const fn token_to_bit(kind: SyntaxKind) -> u64 {
let bit_id = kind.into_u16() + 1;
1 << (bit_id as u64)
}
pub(crate) fn bit_index_to_token_or_end(bit_index: u16) -> Option<SyntaxKind> {
match bit_index {
0 => None,
x => Some(SyntaxKind::try_from(x - 1).unwrap()),
}
}
}
impl std::fmt::Debug for TokenSet {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(fmt, "TokenSet {{")?;
let mut is_first = true;
for token in self.iter() {
if is_first {
is_first = false
} else {
write!(fmt, ", ")?;
}
write!(fmt, "{:?}", token)?;
}
write!(fmt, "}}")
}
}
impl core::ops::BitOr for TokenSet {
type Output = TokenSet;
fn bitor(self, rhs: Self) -> Self::Output {
self.union(rhs)
}
}
pub struct TokenSetIter {
token_set: TokenSet,
bit_index: u16,
}
impl Iterator for TokenSetIter {
type Item = Option<SyntaxKind>;
fn next(&mut self) -> Option<Self::Item> {
while self.bit_index < 64 {
let old_bit_index = self.bit_index;
let has_bit = self.token_set.0 & (1u64 << u64::from(old_bit_index)) != 0;
self.bit_index += 1;
if has_bit {
return Some(TokenSet::bit_index_to_token_or_end(old_bit_index));
}
}
None
}
}
macro_rules! token_set {
(None) => {
crate::token_set::TokenSet::EMPTY.insert_end()
};
(None, $($token:expr),+) => {
crate::token_set::TokenSet::EMPTY.insert_end() $(.insert_token($token))*
};
($($token:expr),*) => {
crate::token_set::TokenSet::EMPTY $(.insert_token($token))*
};
}
#[test]
fn test_empty() {
let set = token_set!();
assert!(!set.contains(None));
assert!(!set.contains(Some(SyntaxKind::TokenText)));
assert!(!set.contains(Some(SyntaxKind::TokenSlash)));
assert!(!set.contains(Some(SyntaxKind::TokenColon)));
}
#[test]
fn test_only_end() {
let set = token_set!(None);
assert!(set.contains(None));
assert!(!set.contains(Some(SyntaxKind::TokenText)));
assert!(!set.contains(Some(SyntaxKind::TokenSlash)));
assert!(!set.contains(Some(SyntaxKind::TokenColon)));
}
#[test]
fn test_only_ident() {
let set = token_set!(SyntaxKind::TokenText);
assert!(!set.contains(None));
assert!(set.contains(Some(SyntaxKind::TokenText)));
assert!(!set.contains(Some(SyntaxKind::TokenSlash)));
assert!(!set.contains(Some(SyntaxKind::TokenColon)));
}
#[test]
fn test_end_and_ident() {
let set = token_set!(None, SyntaxKind::TokenText);
assert!(set.contains(None));
assert!(set.contains(Some(SyntaxKind::TokenText)));
assert!(!set.contains(Some(SyntaxKind::TokenSlash)));
assert!(!set.contains(Some(SyntaxKind::TokenColon)));
}
#[test]
fn test_ident_and_semicolon() {
let set = token_set!(SyntaxKind::TokenText, SyntaxKind::TokenColon);
assert!(!set.contains(None));
assert!(set.contains(Some(SyntaxKind::TokenText)));
assert!(!set.contains(Some(SyntaxKind::TokenSlash)));
assert!(set.contains(Some(SyntaxKind::TokenColon)));
}
#[test]
fn test_iter_empty() {
let set = token_set!();
let mut it = set.iter();
assert_eq!(it.next(), None);
}
#[test]
fn test_iter_only_end() {
let set = token_set!(None);
let mut it = set.iter();
assert_eq!(it.next(), Some(None));
assert_eq!(it.next(), None);
}
#[test]
fn test_iter_ident_and_semicolon() {
let set = token_set!(SyntaxKind::TokenText, SyntaxKind::TokenColon);
let mut it = set.iter();
assert_eq!(it.next(), Some(Some(SyntaxKind::TokenText)));
assert_eq!(it.next(), Some(Some(SyntaxKind::TokenColon)));
assert_eq!(it.next(), None);
}