use super::ident_sequence::IdentSequence;
use crate::input::{code_points::LEFT_PARENTHESIS, Filtered};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IdentToken<'a>(IdentSequence<'a>);
impl<'a> IdentToken<'a> {
pub const fn new_const(s: &'a str) -> Self {
let (v, stream) = Self::consume(Filtered::new(s));
if let Some(v) = v {
let remaining = stream.0.as_str();
konst::const_panic::concat_assert!(
remaining.is_empty(),
"invalid tokens after ident token: ",
remaining
);
v
} else {
konst::const_panic::concat_panic!("invalid ident token: ", s);
}
}
const fn consume(stream: Filtered<'a>) -> (Option<Self>, Filtered<'a>) {
let original = stream.copy();
let (ident_sequence, stream) = IdentSequence::consume(stream);
let Some(ident_sequence) = ident_sequence else {
return (None, stream);
};
if matches!(
stream.first_n_code_points::<1>().as_char_slice(),
[LEFT_PARENTHESIS]
) {
return (None, original);
}
(Some(IdentToken(ident_sequence)), stream)
}
pub(crate) const fn from_ident_sequence(v: IdentSequence<'a>) -> Self {
Self(v)
}
pub(crate) const fn as_ident_sequence(&self) -> IdentSequence<'a> {
self.0
}
pub const fn original_str(&self) -> &'a str {
self.0.original_str()
}
}
#[cfg(feature = "alloc")]
mod alloc {
use alloc::borrow::Cow;
use super::IdentToken;
impl<'a> IdentToken<'a> {
pub fn unescape(&self) -> Cow<'a, str> {
self.0.unescape()
}
}
}
#[cfg(test)]
mod tests {
use super::IdentToken;
const _: () = {
assert!(matches!(
IdentToken::new_const("s")
.as_ident_sequence()
.original_str()
.as_bytes(),
b"s"
));
assert!(IdentToken::new_const("\0red")
.as_ident_sequence()
.matches_chars(&[char::REPLACEMENT_CHARACTER, 'r', 'e', 'd']))
};
}