#![allow(dead_code)]
use logos::Logos;
use rowan::Language;
#[derive(Logos, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u16)]
pub enum SyntaxKind {
#[token("(")]
ParenOpen = 0,
#[token(")")]
ParenClose,
#[token("[")]
BracketOpen,
#[token("]")]
BracketClose,
#[token("{")]
BraceOpen,
#[token("}")]
BraceClose,
#[token("::")]
DoubleColon,
#[token(":")]
Colon,
#[token("=")]
Equals,
#[token("!")]
Negation,
#[token("-")]
Minus,
#[token("~")]
Tilde,
#[token("_")]
Underscore,
#[token("*")]
Star,
#[token("+")]
Plus,
#[token("?")]
Question,
#[token("*?")]
StarQuestion,
#[token("+?")]
PlusQuestion,
#[token("??")]
QuestionQuestion,
#[token("/")]
Slash,
#[token(",")]
Comma,
#[token("|")]
Pipe,
#[regex(r#""(?:[^"\\]|\\.)*""#)]
#[regex(r"'(?:[^'\\]|\\.)*'")]
#[doc(hidden)]
StringLiteral,
DoubleQuote,
SingleQuote,
StrVal,
#[token("ERROR")]
KwError,
#[token("MISSING")]
KwMissing,
#[regex(r"[a-zA-Z][a-zA-Z0-9_.\-]*")]
Id,
#[token(".")]
Dot,
#[regex(r"@[a-zA-Z][a-zA-Z0-9_]*")]
CaptureToken,
#[regex(r"@_[a-zA-Z0-9_]*")]
SuppressiveCapture,
#[token("@")]
At,
#[regex(r"[ \t]+")]
Whitespace,
#[token("\n")]
#[token("\r\n")]
Newline,
#[regex(r"//[^\n]*", allow_greedy = true)]
#[regex(r";[^\n]*", allow_greedy = true)]
LineComment,
#[regex(r"/\*(?:[^*]|\*[^/])*\*/")]
BlockComment,
#[token("==")]
OpEq,
#[token("!=")]
OpNe,
#[token("^=")]
OpStartsWith,
#[token("$=")]
OpEndsWith,
#[token("*=")]
OpContains,
#[token("=~")]
OpRegexMatch,
#[token("!~")]
OpRegexNoMatch,
#[regex(r"=~[ \t\r\n]*/", lex_regex_predicate)]
RegexPredicateMatch,
#[regex(r"!~[ \t\r\n]*/", lex_regex_predicate)]
RegexPredicateNoMatch,
RegexLiteral,
RegexContent,
#[regex(r"<[a-zA-Z_:][a-zA-Z0-9_:\.\-]*(?:\s+[^>]*)?>")]
#[regex(r"</[a-zA-Z_:][a-zA-Z0-9_:\.\-]*\s*>")]
#[regex(r"<[a-zA-Z_:][a-zA-Z0-9_:\.\-]*\s*/\s*>")]
XMLGarbage,
#[regex(r"#[a-zA-Z_][a-zA-Z0-9_]*[?!]?")]
TsPredicate,
Garbage,
Error,
Root,
Tree,
Ref,
Str,
Field,
Capture,
Type,
Quantifier,
Seq,
Alt,
Branch,
Wildcard,
Anchor,
NegatedField,
Def,
NodePredicate,
Regex,
#[doc(hidden)]
__LAST,
}
use SyntaxKind::*;
fn lex_regex_predicate(lexer: &mut logos::Lexer<SyntaxKind>) -> bool {
let remaining = lexer.remainder();
let mut backslash_count = 0;
for (i, c) in remaining.char_indices() {
if c == '/' && backslash_count % 2 == 0 {
lexer.bump(i + 1);
return true;
}
backslash_count = if c == '\\' { backslash_count + 1 } else { 0 };
}
lexer.bump(remaining.len());
true
}
impl SyntaxKind {
#[inline]
pub fn is_trivia(self) -> bool {
matches!(self, Whitespace | Newline | LineComment | BlockComment)
}
#[inline]
pub fn is_error(self) -> bool {
matches!(self, Error | XMLGarbage | Garbage | TsPredicate)
}
}
impl From<SyntaxKind> for rowan::SyntaxKind {
#[inline]
fn from(kind: SyntaxKind) -> Self {
Self(kind as u16)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum QLang {}
impl Language for QLang {
type Kind = SyntaxKind;
fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
assert!(raw.0 < __LAST as u16);
unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
}
fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
kind.into()
}
}
pub type SyntaxNode = rowan::SyntaxNode<QLang>;
pub type SyntaxToken = rowan::SyntaxToken<QLang>;
pub type SyntaxElement = rowan::NodeOrToken<SyntaxNode, SyntaxToken>;
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TokenSet(u128);
impl TokenSet {
pub const EMPTY: TokenSet = TokenSet(0);
#[inline]
pub const fn new(kinds: &[SyntaxKind]) -> Self {
let mut bits = 0u128;
let mut i = 0;
while i < kinds.len() {
let kind = kinds[i] as u16;
assert!(kind < 128, "SyntaxKind value exceeds TokenSet capacity");
bits |= 1 << kind;
i += 1;
}
TokenSet(bits)
}
#[inline]
pub const fn single(kind: SyntaxKind) -> Self {
let kind = kind as u16;
assert!(kind < 128, "SyntaxKind value exceeds TokenSet capacity");
TokenSet(1 << kind)
}
#[inline]
pub const fn contains(&self, kind: SyntaxKind) -> bool {
let kind = kind as u16;
if kind >= 128 {
return false;
}
self.0 & (1 << kind) != 0
}
#[inline]
pub const fn union(self, other: TokenSet) -> TokenSet {
TokenSet(self.0 | other.0)
}
}
impl std::fmt::Debug for TokenSet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut list = f.debug_set();
for i in 0..128u16 {
if self.0 & (1 << i) != 0 && i < __LAST as u16 {
let kind: SyntaxKind = unsafe { std::mem::transmute(i) };
list.entry(&kind);
}
}
list.finish()
}
}
pub mod token_sets {
use super::*;
pub const EXPR_FIRST_TOKENS: TokenSet = TokenSet::new(&[
ParenOpen,
BracketOpen,
BraceOpen,
Underscore,
Id,
DoubleQuote,
SingleQuote,
Dot,
Negation,
Minus,
KwError,
KwMissing,
]);
pub const ROOT_EXPR_FIRST_TOKENS: TokenSet = TokenSet::new(&[
ParenOpen,
BracketOpen,
BraceOpen,
Underscore,
Id,
DoubleQuote,
SingleQuote,
KwError,
KwMissing,
]);
pub const QUANTIFIERS: TokenSet = TokenSet::new(&[
Star,
Plus,
Question,
StarQuestion,
PlusQuestion,
QuestionQuestion,
]);
pub const TRIVIA: TokenSet = TokenSet::new(&[Whitespace, Newline, LineComment, BlockComment]);
pub const SEPARATORS: TokenSet = TokenSet::new(&[Comma, Pipe]);
pub const TREE_RECOVERY_TOKENS: TokenSet = TokenSet::new(&[ParenOpen, BracketOpen, BraceOpen]);
pub const ALT_RECOVERY_TOKENS: TokenSet = TokenSet::new(&[ParenClose]);
pub const FIELD_RECOVERY_TOKENS: TokenSet = TokenSet::new(&[
ParenClose,
BracketClose,
BraceClose,
CaptureToken,
SuppressiveCapture,
Colon,
]);
pub const ROOT_RECOVERY_TOKENS: TokenSet =
TokenSet::new(&[ParenOpen, BracketOpen, BraceOpen, Id]);
pub const DEF_RECOVERY_TOKENS: TokenSet =
TokenSet::new(&[ParenOpen, BracketOpen, BraceOpen, Id, Equals]);
pub const SEQ_RECOVERY_TOKENS: TokenSet =
TokenSet::new(&[BraceClose, ParenClose, BracketClose]);
pub const PREDICATE_OPS: TokenSet = TokenSet::new(&[
OpEq,
OpNe,
OpStartsWith,
OpEndsWith,
OpContains,
OpRegexMatch,
OpRegexNoMatch,
]);
}