use super::{LexError, Lexer, Tok};
impl<'input> Iterator for Lexer<'input> {
type Item = std::result::Result<(usize, Tok, usize), LexError>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(tok) = self.pending.pop_front() {
return Some(tok);
}
if self.pos >= self.input.len() {
return None;
}
if let Some(res) = self.lex_arrow_and_label() {
return Some(res);
}
if let Some(sep) = self.lex_sep() {
self.allow_header_direction = false;
return Some(Ok(sep));
}
self.skip_ws();
if self.pos >= self.input.len() {
return None;
}
if let Some(sep) = self.lex_sep() {
self.allow_header_direction = false;
return Some(Ok(sep));
}
if let Some(sep) = self.lex_comment() {
self.allow_header_direction = false;
return Some(Ok(sep));
}
self.skip_ws();
if self.pos >= self.input.len() {
return None;
}
let start = self.pos;
if let Some(tok) = self.lex_direction_stmt() {
return Some(tok);
}
if let Some(res) = self.lex_style_stmt() {
return Some(res);
}
if let Some(res) = self.lex_classdef_stmt() {
return Some(res);
}
if let Some(res) = self.lex_class_assign_stmt() {
return Some(res);
}
if let Some(res) = self.lex_click_stmt() {
return Some(res);
}
if let Some(res) = self.lex_link_style_stmt() {
return Some(res);
}
if let Some(res) = self.lex_shape_data() {
return Some(res);
}
if self.starts_with_kw("flowchart-elk") {
self.pos += "flowchart-elk".len();
self.allow_header_direction = true;
return Some(Ok((start, Tok::KwFlowchartElk, self.pos)));
}
if self.starts_with_kw("swimlane-beta") {
self.pos += "swimlane-beta".len();
self.allow_header_direction = true;
return Some(Ok((start, Tok::KwSwimlane, self.pos)));
}
if self.starts_with_kw("flowchart") {
self.pos += "flowchart".len();
self.allow_header_direction = true;
return Some(Ok((start, Tok::KwFlowchart, self.pos)));
}
if self.starts_with_kw("graph") {
self.pos += "graph".len();
self.allow_header_direction = true;
return Some(Ok((start, Tok::KwGraph, self.pos)));
}
if self.starts_with_kw("subgraph") {
self.pos += "subgraph".len();
let keyword_end = self.pos;
if let Some(header) = self.lex_subgraph_header_after_keyword(start) {
self.pending.push_back(header);
}
return Some(Ok((start, Tok::KwSubgraph, keyword_end)));
}
if self.starts_with_kw("end") {
self.pos += "end".len();
return Some(Ok((start, Tok::KwEnd, self.pos)));
}
if let Some(tok) = self.lex_style_sep() {
return Some(Ok(tok));
}
if let Some(tok) = self.lex_direction() {
return Some(Ok(tok));
}
self.allow_header_direction = false;
if let Some(res) = self.lex_node_label() {
return Some(res);
}
if let Some(tok) = self.lex_edge_id() {
return Some(Ok(tok));
}
if let Some(tok) = self.lex_id() {
return Some(Ok(tok));
}
if let Some(tok) = self.lex_amp() {
return Some(Ok(tok));
}
self.pos += self.input[start..].chars().next().unwrap().len_utf8();
Some(Err(LexError::with_span(
format!("Unexpected character at {start}"),
crate::SourceSpan::new(start, self.pos),
)))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unsupported_unicode_recovery_keeps_character_boundaries() {
let mut lexer = Lexer::new("😀A");
assert!(lexer.next().unwrap().is_err());
let (start, token, end) = lexer.next().unwrap().unwrap();
assert!(matches!(token, Tok::Id(ref id) if id == "A"));
assert_eq!((start, end), (4, 5));
assert!(lexer.next().is_none());
}
}