1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Parsing entry points and context-aware single-line parsing.
//!
//! Provides [`Script::parse`], the [`Script::builder`] constructor, and the
//! format-aware helpers used to parse individual style and event lines against
//! the script's stored format definitions.
use crate::parser::ast::{Event, Style};
use crate::parser::errors::ParseError;
use crate::parser::main::Parser;
use crate::Result;
use super::builder::ScriptBuilder;
use super::Script;
impl<'a> Script<'a> {
/// Parse ASS script from source text with zero-copy design
///
/// Performs full validation and partial error recovery. Returns script
/// even with errors - check `issues()` for problems.
///
/// # Performance
///
/// Target <5ms for 1KB typical scripts. Uses minimal allocations via
/// zero-copy spans referencing input text.
///
/// # Example
///
/// ```rust
/// # use ass_core::parser::Script;
/// let script = Script::parse("[Script Info]\nTitle: Test")?;
/// assert_eq!(script.version(), ass_core::ScriptVersion::AssV4);
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// # Errors
///
/// Returns an error if the source contains malformed section headers or
/// other unrecoverable syntax errors.
pub fn parse(source: &'a str) -> Result<Self> {
let parser = Parser::new(source);
Ok(parser.parse())
}
/// Create a new script builder for parsing with optional extensions
///
/// The builder pattern allows configuration of parsing options including
/// extension registry for custom tag handlers and section processors.
///
/// # Example
///
/// ```rust
/// # use ass_core::parser::Script;
/// # #[cfg(feature = "plugins")]
/// # use ass_core::plugin::ExtensionRegistry;
/// # #[cfg(feature = "plugins")]
/// let registry = ExtensionRegistry::new();
/// # #[cfg(feature = "plugins")]
/// let script = Script::builder()
/// .with_registry(®istry)
/// .parse("[Script Info]\nTitle: Test")?;
/// # #[cfg(not(feature = "plugins"))]
/// let script = Script::builder()
/// .parse("[Script Info]\nTitle: Test")?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
#[must_use]
pub const fn builder() -> ScriptBuilder<'a> {
ScriptBuilder::new()
}
/// Parse a style line with context from the script
///
/// Uses the script's stored format for [V4+ Styles] section if available,
/// otherwise falls back to default format.
///
/// # Arguments
///
/// * `line` - The style line to parse (without "Style:" prefix)
/// * `line_number` - The line number for error reporting
///
/// # Returns
///
/// Parsed Style or error if the line is malformed
///
/// # Errors
///
/// Returns [`ParseError::InsufficientFields`] if the line has fewer fields than expected
pub fn parse_style_line_with_context(
&self,
line: &'a str,
line_number: u32,
) -> core::result::Result<Style<'a>, ParseError> {
use crate::parser::sections::StylesParser;
let format = self.styles_format.as_deref().unwrap_or(&[
"Name",
"Fontname",
"Fontsize",
"PrimaryColour",
"SecondaryColour",
"OutlineColour",
"BackColour",
"Bold",
"Italic",
"Underline",
"StrikeOut",
"ScaleX",
"ScaleY",
"Spacing",
"Angle",
"BorderStyle",
"Outline",
"Shadow",
"Alignment",
"MarginL",
"MarginR",
"MarginV",
"Encoding",
]);
StylesParser::parse_style_line(line, format, line_number)
}
/// Parse an event line with context from the script
///
/// Uses the script's stored format for `[Events\]` section if available,
/// otherwise falls back to default format.
///
/// # Arguments
///
/// * `line` - The event line to parse (e.g., "Dialogue: 0,0:00:00.00,0:00:05.00,Default,,0,0,0,,Text")
/// * `line_number` - The line number for error reporting
///
/// # Returns
///
/// Parsed Event or error if the line is malformed
///
/// # Errors
///
/// Returns [`ParseError::InvalidEventType`] if the line doesn't start with a valid event type
/// Returns [`ParseError::InsufficientFields`] if the line has fewer fields than expected
pub fn parse_event_line_with_context(
&self,
line: &'a str,
line_number: u32,
) -> core::result::Result<Event<'a>, ParseError> {
use crate::parser::sections::EventsParser;
let format = self.events_format.as_deref().unwrap_or(&[
"Layer", "Start", "End", "Style", "Name", "MarginL", "MarginR", "MarginV", "Effect",
"Text",
]);
EventsParser::parse_event_line(line, format, line_number)
}
}