use crate::syntax::kind::SyntaxKind;
use logos::Logos;
use rowan::{TextRange, TextSize};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LexedToken {
pub kind: SyntaxKind,
pub range: TextRange,
}
#[derive(Debug, Clone)]
pub struct Lexed<'a> {
src: &'a str,
tokens: Vec<LexedToken>,
}
impl<'a> Lexed<'a> {
pub fn src(&self) -> &'a str {
self.src
}
pub fn len(&self) -> usize {
self.tokens.len()
}
pub fn is_empty(&self) -> bool {
self.tokens.is_empty()
}
pub fn kind(&self, i: usize) -> SyntaxKind {
self.tokens.get(i).map_or(SyntaxKind::EOF, |t| t.kind)
}
pub fn text(&self, i: usize) -> &'a str {
match self.tokens.get(i) {
Some(t) => &self.src[t.range],
None => "",
}
}
pub fn range(&self, i: usize) -> TextRange {
self.tokens
.get(i)
.map_or_else(|| TextRange::empty(self.end()), |t| t.range)
}
pub fn end(&self) -> TextSize {
self.tokens
.last()
.map_or_else(|| TextSize::new(0), |t| t.range.end())
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = (SyntaxKind, &'a str)> + '_ {
let src = self.src;
self.tokens.iter().map(move |t| (t.kind, &src[t.range]))
}
}
pub fn lex(src: &str) -> Lexed<'_> {
let src_len = u32::try_from(src.len()).expect("source larger than 4 GiB");
let mut out: Vec<LexedToken> = Vec::with_capacity(src.len() / 4);
let mut lexer = SyntaxKind::lexer(src);
while let Some(result) = lexer.next() {
let span = lexer.span();
let range = TextRange::new(
TextSize::from(span.start as u32),
TextSize::from(span.end as u32),
);
debug_assert!(u32::from(range.end()) <= src_len);
let kind = match result {
Ok(kind) => kind,
Err(()) => {
if let Some(last) = out.last_mut()
&& last.kind == SyntaxKind::LEX_ERROR
&& last.range.end() == range.start()
{
last.range = TextRange::new(last.range.start(), range.end());
continue;
}
SyntaxKind::LEX_ERROR
}
};
out.push(LexedToken { kind, range });
}
Lexed { src, tokens: out }
}