use super::{AssTokenizer, Token, TokenContext, TokenType};
use crate::Result;
impl<'a> AssTokenizer<'a> {
pub fn next_token(&mut self) -> Result<Option<Token<'a>>> {
if self.context.allows_whitespace_skipping() {
self.scanner.navigator_mut().skip_whitespace();
}
if self.scanner.navigator().is_at_end() {
return Ok(None);
}
let start_pos = self.scanner.navigator().position();
let start_line = self.scanner.navigator().line();
let start_column = self.scanner.navigator().column();
let current_char = self.scanner.navigator_mut().peek_char()?;
let token_type = match (current_char, self.context) {
('[', _) => {
self.context = TokenContext::SectionHeader;
self.scanner.scan_section_header()
}
(']', TokenContext::SectionHeader) => {
self.context = TokenContext::Document;
self.scanner.navigator_mut().advance_char()?;
Ok(TokenType::SectionClose)
}
(':', TokenContext::Document) => {
self.context = self.context.enter_field_value();
self.scanner.navigator_mut().advance_char()?;
Ok(TokenType::Colon)
}
('{', _) => {
self.context = TokenContext::StyleOverride;
self.scanner.scan_style_override()
}
('}', TokenContext::StyleOverride) => {
self.context = TokenContext::Document;
self.scanner.navigator_mut().advance_char()?;
Ok(TokenType::OverrideClose)
}
(',', _) => {
self.scanner.navigator_mut().advance_char()?;
Ok(TokenType::Comma)
}
('\n' | '\r', _) => {
self.context = self.context.reset_to_document();
self.scanner.navigator_mut().advance_char()?;
if current_char == '\r' && self.scanner.navigator_mut().peek_char()? == '\n' {
self.scanner.navigator_mut().advance_char()?;
}
Ok(TokenType::Newline)
}
(';', TokenContext::Document) => self.scanner.scan_comment(),
('!', TokenContext::Document) => {
if self.scanner.navigator().peek_next() == Ok(':') {
self.scanner.scan_comment()
} else {
self.scanner.scan_text(self.context)
}
}
('}', _) => {
self.scanner.navigator_mut().advance_char()?;
Ok(TokenType::Text)
}
(']', _) => {
self.scanner.navigator_mut().advance_char()?;
Ok(TokenType::Text)
}
_ => {
if self.context == TokenContext::FieldValue {
self.scanner.scan_field_value()
} else {
self.scanner.scan_text(self.context)
}
}
}?;
let end_pos = self.scanner.navigator().position();
let span = &self.source[start_pos..end_pos];
if start_pos == end_pos && !self.scanner.navigator().is_at_end() {
return Err(crate::utils::CoreError::internal(
"Tokenizer position not advancing",
));
}
Ok(Some(Token {
token_type,
span,
line: start_line,
column: start_column,
}))
}
}