Skip to main content

ass_core/tokenizer/state/
context.rs

1//! Tokenization context tracking for state-aware ASS tokenization.
2//!
3//! Defines [`TokenContext`], which records the current lexical context so the
4//! tokenizer can apply context-sensitive rules for ASS script elements that
5//! have different lexical rules in different contexts.
6
7/// Tokenization context for state-aware parsing
8///
9/// Tracks current parsing context to enable context-sensitive tokenization
10/// of ASS script elements that have different lexical rules in different
11/// contexts.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
13pub enum TokenContext {
14    /// Top-level document parsing
15    ///
16    /// Default state for processing section headers, comments, and
17    /// top-level document structure.
18    #[default]
19    Document,
20
21    /// Inside section header like `[Events]`
22    ///
23    /// Special tokenization rules for section names within square brackets.
24    SectionHeader,
25
26    /// Inside field definition line
27    ///
28    /// Field values have different whitespace and delimiter handling than
29    /// other contexts.
30    FieldValue,
31
32    /// Inside style override block like {\b1}
33    ///
34    /// Override tags use backslash prefixes and have special syntax rules.
35    StyleOverride,
36
37    /// Inside drawing commands (\p1)
38    ///
39    /// Drawing commands use vector graphics syntax with different
40    /// coordinate and command parsing rules.
41    DrawingCommands,
42
43    /// Inside UU-encoded data (fonts/graphics)
44    ///
45    /// Binary data sections use different character validation and
46    /// line parsing rules.
47    UuEncodedData,
48}
49
50impl TokenContext {
51    /// Check if context allows whitespace skipping
52    #[must_use]
53    pub const fn allows_whitespace_skipping(self) -> bool {
54        !matches!(self, Self::FieldValue | Self::UuEncodedData)
55    }
56
57    /// Check if context is inside a delimited block
58    #[must_use]
59    pub const fn is_delimited_block(self) -> bool {
60        matches!(self, Self::SectionHeader | Self::StyleOverride)
61    }
62
63    /// Get expected closing delimiter for context
64    #[must_use]
65    pub const fn closing_delimiter(self) -> Option<char> {
66        match self {
67            Self::SectionHeader => Some(']'),
68            Self::StyleOverride => Some('}'),
69            _ => None,
70        }
71    }
72
73    /// Transition to field value context after colon
74    #[must_use]
75    pub const fn enter_field_value(self) -> Self {
76        match self {
77            Self::Document => Self::FieldValue,
78            other => other,
79        }
80    }
81
82    /// Reset to document context (typically after newline)
83    #[must_use]
84    pub const fn reset_to_document(self) -> Self {
85        Self::Document
86    }
87}