use std::fmt::Debug;
pub trait TokenKind: Clone + PartialEq {
fn unrecognized() -> Self;
fn is_unrecognized(&self) -> bool {
self == &Self::unrecognized()
}
fn eof() -> Self;
fn is_eof(&self) -> bool {
self == &Self::eof()
}
}
#[derive(Debug, PartialEq)]
pub struct Token<'a, K: TokenKind> {
pub kind: K,
pub start: usize,
pub end: usize,
pub text: &'a str,
pub skip: bool,
pub next: Option<Box<Token<'a, K>>>,
pub skipped: Vec<Token<'a, K>>,
pub captures: Option<Vec<Option<(usize, usize)>>>,
}
impl<'a, K: TokenKind> Token<'a, K> {
pub fn new(source: &'a str, kind: K, start: usize, end: usize) -> Token<'a, K> {
Token {
kind,
start,
end,
text: &source[start..end],
skip: false,
skipped: vec![],
next: None,
captures: None,
}
}
pub fn from_text(kind: K, text: &'a str, start: usize) -> Token<'a, K> {
Token {
kind,
start,
end: start + text.len(),
text,
skip: false,
skipped: vec![],
next: None,
captures: None,
}
}
pub fn eof(source: &'a str) -> Token<'a, K> {
Token {
kind: K::eof(),
start: source.len(),
end: source.len(),
text: "",
skip: false,
next: None,
skipped: vec![],
captures: None,
}
}
pub fn skip(mut self, skip: bool) -> Self {
self.skip = skip;
self
}
pub fn skipped(mut self, skipped: Vec<Token<'a, K>>) -> Self {
self.skipped = skipped;
self
}
pub fn next(mut self, next: Option<Box<Token<'a, K>>>) -> Self {
self.next = next;
self
}
pub fn captures(mut self, captures: Option<Vec<Option<(usize, usize)>>>) -> Self {
self.captures = captures;
self
}
pub fn get_capture(&self, idx: usize) -> Option<TokenCapture<'a>> {
self
.captures
.as_ref()
.and_then(|captures| captures[idx])
.map(|(start, end)| TokenCapture {
text: &self.text[start..end],
start,
end,
})
}
}
#[derive(Debug, PartialEq)]
pub struct TokenCapture<'a> {
pub text: &'a str,
pub start: usize,
pub end: usize,
}
#[cfg(test)]
impl TokenKind for &'static str {
fn unrecognized() -> Self {
"UNRECOGNIZED"
}
fn eof() -> Self {
"EOF"
}
}