#![deny(warnings)]
use crate::scanner::Scanner;
pub struct EbnfTokenizer<I: Iterator<Item = char>> {
input: Scanner<I>,
lookahead: Vec<String>,
}
impl<I: Iterator<Item = char>> EbnfTokenizer<I> {
pub fn new(source: I) -> Self {
EbnfTokenizer {
input: Scanner::new(source),
lookahead: Vec::new(),
}
}
pub fn scanner(source: I) -> Scanner<Self> {
Scanner::new(Self::new(source))
}
}
impl<I: Iterator<Item = char>> Iterator for EbnfTokenizer<I> {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
if !self.lookahead.is_empty() {
return self.lookahead.pop();
}
let s = &mut self.input;
s.scan_whitespace();
if s.accept(&'#').is_some() {
while let Some(nl) = s.next() {
if nl == '\n' {
s.extract(); return self.next();
}
}
}
if s.accept_any(&['[', ']', '{', '}', '(', ')', '|', ';'])
.is_some()
{
return Some(s.extract_string());
}
let backtrack = s.buffer_pos();
if s.accept(&':').is_some() {
if s.accept(&'=').is_some() {
return Some(s.extract_string());
}
s.set_buffer_pos(backtrack);
}
let backtrack = s.buffer_pos();
if let Some(q) = s.accept_any(&['"', '\'']) {
while let Some(n) = s.next() {
if n == q {
self.lookahead.push(n.to_string());
let v = s.extract_string();
self.lookahead.push(v[1..v.len() - 1].to_string());
return Some(q.to_string());
}
}
s.set_buffer_pos(backtrack);
}
let backtrack = s.buffer_pos();
s.accept(&'@');
if let Some(id) = s.scan_identifier() {
return Some(id);
}
s.set_buffer_pos(backtrack);
None
}
}