use crate::SyntaxKind;
#[derive(Default, Copy, Clone)]
pub struct SyntaxSet(u128);
impl SyntaxSet {
pub const fn new() -> Self {
Self(0)
}
pub const fn add(self, kind: SyntaxKind) -> Self {
assert!((kind as u8) < BITS);
Self(self.0 | bit(kind))
}
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
pub const fn contains(&self, kind: SyntaxKind) -> bool {
(kind as u8) < BITS && (self.0 & bit(kind)) != 0
}
}
const BITS: u8 = 128;
const fn bit(kind: SyntaxKind) -> u128 {
1 << (kind as usize)
}
macro_rules! syntax_set {
($($kind:ident),* $(,)?) => {{
const SET: crate::set::SyntaxSet = crate::set::SyntaxSet::new()
$(.add(crate::SyntaxKind:: $kind))*;
SET
}}
}
pub(crate) use syntax_set;
pub const STMT: SyntaxSet = syntax_set!(Let, Set, Show, Import, Include, Return);
pub const MATH_EXPR: SyntaxSet = syntax_set!(
Hash,
MathIdent,
FieldAccess,
Dot,
Comma,
Semicolon,
RightParen,
Text,
MathText,
MathShorthand,
Linebreak,
MathAlignPoint,
Escape,
Str,
Root,
Prime,
);
pub const CODE_EXPR: SyntaxSet = CODE_PRIMARY.union(UNARY_OP);
pub const ATOMIC_CODE_EXPR: SyntaxSet = ATOMIC_CODE_PRIMARY;
pub const CODE_PRIMARY: SyntaxSet = ATOMIC_CODE_PRIMARY.add(SyntaxKind::Underscore);
pub const ATOMIC_CODE_PRIMARY: SyntaxSet = syntax_set!(
Ident,
LeftBrace,
LeftBracket,
LeftParen,
Dollar,
Let,
Set,
Show,
Context,
If,
While,
For,
Import,
Include,
Break,
Continue,
Return,
None,
Auto,
Int,
Float,
Bool,
Numeric,
Str,
Label,
Raw,
);
pub const UNARY_OP: SyntaxSet = syntax_set!(Plus, Minus, Not);
pub const BINARY_OP: SyntaxSet = syntax_set!(
Plus, Minus, Star, Slash, And, Or, EqEq, ExclEq, Lt, LtEq, Gt, GtEq, Eq, In, PlusEq,
HyphEq, StarEq, SlashEq,
);
pub const ARRAY_OR_DICT_ITEM: SyntaxSet = CODE_EXPR.add(SyntaxKind::Dots);
pub const ARG: SyntaxSet = CODE_EXPR.add(SyntaxKind::Dots);
pub const PARAM: SyntaxSet = PATTERN.add(SyntaxKind::Dots);
pub const DESTRUCTURING_ITEM: SyntaxSet = PATTERN.add(SyntaxKind::Dots);
pub const PATTERN: SyntaxSet =
PATTERN_LEAF.add(SyntaxKind::LeftParen).add(SyntaxKind::Underscore);
pub const PATTERN_LEAF: SyntaxSet = ATOMIC_CODE_EXPR;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_set() {
let set = SyntaxSet::new().add(SyntaxKind::And).add(SyntaxKind::Or);
assert!(set.contains(SyntaxKind::And));
assert!(set.contains(SyntaxKind::Or));
assert!(!set.contains(SyntaxKind::Not));
}
}