use std::{iter::Peekable, str::Chars};
use crate::position::*;
pub struct Scanner<'a> {
start: BytePos,
current: BytePos,
source: &'a str,
it: Peekable<Chars<'a>>,
}
impl<'a> Scanner<'a> {
pub fn new(buf: &str) -> Scanner {
Scanner {
current: BytePos::default(),
start: BytePos::default(),
source: buf,
it: buf.chars().peekable(),
}
}
pub fn source(&self) -> &str {
self.source
}
pub fn start(&self) -> BytePos {
self.start
}
pub fn current(&self) -> BytePos {
self.current
}
pub fn shift(&mut self) {
self.start = self.current;
}
pub fn slice(&self) -> &str {
&self.source[self.start.0..self.current.0]
}
pub fn next(&mut self) -> Option<char> {
let next = self.it.next();
if let Some(c) = next {
self.current = self.current.shift(c);
}
next
}
pub fn peek(&mut self) -> Option<&char> {
self.it.peek()
}
pub fn consume_if(&mut self, predicate: impl Fn(char) -> bool) -> bool {
if let Some(c) = self.peek() {
if predicate(*c) {
self.next();
return true;
}
}
false
}
pub fn if_next<P>(&mut self, predicate: P) -> bool
where
P: Fn(char) -> bool,
{
if let Some(c) = self.peek() {
predicate(*c)
} else {
false
}
}
pub fn consume_if_next<P>(&mut self, predicate: P) -> bool
where
P: Fn(char) -> bool,
{
let mut it: Peekable<Chars<'a>> = self.it.clone();
match it.next() {
Some(_) => {
if let Some(c) = it.peek() {
if predicate(*c) {
self.next().unwrap();
return true;
}
}
return false;
}
None => return false,
}
}
pub fn consume_while<P>(&mut self, predicate: P) -> Vec<char>
where
P: Fn(char) -> bool,
{
let mut consumed = Vec::new();
while let Some(&c) = self.peek() {
if predicate(c) {
consumed.push(c);
self.next().unwrap();
} else {
break;
}
}
consumed
}
pub fn next_match(&mut self, expected: char) -> bool {
if self.peek() == Some(&expected) {
self.next();
true
} else {
false
}
}
pub fn with_span<T>(&self, token_type: T) -> WithSpan<T> {
WithSpan::new_unchecked(token_type, self.start.0, self.current.0)
}
pub fn iterator(&self) -> impl Iterator<Item = char> + use<'a> {
self.it.clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_next() {
let mut scanner = Scanner::new("123🦀€é");
assert_eq!(scanner.slice(), "");
scanner.next();
assert_eq!(scanner.slice(), "1");
scanner.next();
assert_eq!(scanner.slice(), "12");
scanner.next();
assert_eq!(scanner.slice(), "123");
scanner.next();
assert_eq!(scanner.slice(), "123🦀");
scanner.next();
assert_eq!(scanner.slice(), "123🦀€");
scanner.next();
assert_eq!(scanner.slice(), "123🦀€é");
}
#[test]
fn test_peek() {
let mut scanner = Scanner::new("123🦀€é");
assert_eq!(scanner.peek(), Some(&'1'));
scanner.next();
assert_eq!(scanner.peek(), Some(&'2'));
scanner.next();
assert_eq!(scanner.peek(), Some(&'3'));
scanner.next();
assert_eq!(scanner.peek(), Some(&'🦀'));
scanner.next();
assert_eq!(scanner.peek(), Some(&'€'));
scanner.next();
assert_eq!(scanner.peek(), Some(&'é'));
scanner.next();
assert_eq!(scanner.peek(), None);
}
#[test]
fn test_consume_if() {
let mut scanner = Scanner::new("123abc");
assert!(scanner.consume_if(|c| c.is_numeric()));
assert_eq!(scanner.slice(), "1");
assert!(scanner.consume_if(|c| c.is_numeric()));
assert_eq!(scanner.slice(), "12");
assert!(scanner.consume_if(|c| c.is_numeric()));
assert_eq!(scanner.slice(), "123");
assert!(!scanner.consume_if(|c| c.is_numeric()));
assert_eq!(scanner.slice(), "123");
}
#[test]
fn test_consume_if_next() {
let mut scanner = Scanner::new("123abc");
assert!(scanner.consume_if_next(|c| c.is_numeric()));
assert_eq!(scanner.slice(), "1");
assert!(scanner.consume_if_next(|c| c.is_numeric()));
assert_eq!(scanner.slice(), "12");
assert!(!scanner.consume_if_next(|c| c.is_numeric()));
assert_eq!(scanner.slice(), "12");
}
#[test]
fn test_if_next() {
let mut scanner = Scanner::new("123abc");
assert!(scanner.if_next(|c| c.is_numeric()));
assert_eq!(scanner.slice(), "");
}
}