Skip to main content

ass_core/tokenizer/scanner/
token_scanner.rs

1//! Token scanner type and its primary scanning routines.
2//!
3//! Defines the [`TokenScanner`] type and the scanning methods for section
4//! headers, style override blocks, and comment lines.
5
6use super::navigator::CharNavigator;
7use crate::tokenizer::tokens::TokenType;
8use crate::Result;
9
10/// Scanner for different token types
11#[derive(Debug, Clone)]
12pub struct TokenScanner<'a> {
13    /// Character navigator for position tracking
14    pub(super) navigator: CharNavigator<'a>,
15    /// Source text reference
16    pub(super) source: &'a str,
17}
18
19impl<'a> TokenScanner<'a> {
20    /// Create new token scanner
21    #[must_use]
22    pub fn new(source: &'a str, position: usize, line: usize, column: usize) -> Self {
23        Self {
24            navigator: CharNavigator::new(source, position, line, column),
25            source,
26        }
27    }
28
29    /// Get current navigator state (mutable)
30    pub fn navigator_mut(&mut self) -> &mut CharNavigator<'a> {
31        &mut self.navigator
32    }
33
34    /// Get current navigator state (immutable)
35    #[must_use]
36    pub const fn navigator(&self) -> &CharNavigator<'a> {
37        &self.navigator
38    }
39
40    /// Scan section header like [Script Info]
41    ///
42    /// # Errors
43    ///
44    /// Returns an error if character navigation fails.
45    pub fn scan_section_header(&mut self) -> Result<TokenType> {
46        self.navigator.advance_char()?; // Skip '['
47
48        while !self.navigator.is_at_end() {
49            let ch = self.navigator.peek_char()?;
50            if ch == ']' {
51                break;
52            }
53            self.navigator.advance_char()?;
54        }
55
56        Ok(TokenType::SectionHeader)
57    }
58
59    /// Scan style override block like {\b1\i1}
60    ///
61    /// # Errors
62    ///
63    /// Returns an error if character navigation fails.
64    pub fn scan_style_override(&mut self) -> Result<TokenType> {
65        self.navigator.advance_char()?; // Skip '{'
66
67        let mut brace_depth = 1;
68        while !self.navigator.is_at_end() && brace_depth > 0 {
69            let ch = self.navigator.peek_char()?;
70            match ch {
71                '{' => brace_depth += 1,
72                '}' => brace_depth -= 1,
73                _ => {}
74            }
75
76            if brace_depth > 0 {
77                self.navigator.advance_char()?;
78            }
79        }
80
81        Ok(TokenType::OverrideBlock)
82    }
83
84    /// Scan comment line starting with ; or !:
85    ///
86    /// # Errors
87    ///
88    /// Returns an error if character navigation fails.
89    pub fn scan_comment(&mut self) -> Result<TokenType> {
90        while !self.navigator.is_at_end() {
91            let ch = self.navigator.peek_char()?;
92            if ch == '\n' || ch == '\r' {
93                break;
94            }
95            self.navigator.advance_char()?;
96        }
97
98        Ok(TokenType::Comment)
99    }
100}