telltale_runtime/compiler/
extension_parser.rs1use crate::ast::{Protocol, Role};
7use crate::compiler::grammar::{GrammarComposer, GrammarCompositionError};
8use crate::compiler::parser::{parse_choreography_str, ParseError};
9use crate::extensions::StatementParser;
10
11pub struct ExtensionParser {
13 grammar_composer: GrammarComposer,
14 parse_buffer: String,
16 annotation_cache: std::collections::HashMap<String, String>,
18}
19
20impl ExtensionParser {
21 pub fn new() -> Self {
23 Self {
24 grammar_composer: GrammarComposer::new(),
25 parse_buffer: String::with_capacity(1024), annotation_cache: std::collections::HashMap::with_capacity(16), }
28 }
29
30 pub fn register_extension<G, P>(
40 &mut self,
41 grammar_ext: G,
42 _statement_parser: P,
43 ) -> Result<(), crate::extensions::ParseError>
44 where
45 G: crate::extensions::GrammarExtension + 'static,
46 P: StatementParser + 'static,
47 {
48 self.grammar_composer.register_extension(grammar_ext)?;
50
51 Ok(())
55 }
56
57 pub fn parse_with_extensions(
59 &mut self,
60 input: &str,
61 ) -> Result<crate::ast::Choreography, ExtensionParseError> {
62 self.parse_buffer.clear();
64 self.annotation_cache.clear();
65
66 self.parse_buffer.reserve(input.len());
68
69 let mut choreography =
73 parse_choreography_str(input).map_err(ExtensionParseError::StandardParseError)?;
74
75 choreography.protocol =
77 self.process_extensions_optimized(choreography.protocol, input, &choreography.roles)?;
78
79 Ok(choreography)
80 }
81
82 fn process_extensions_optimized(
88 &mut self,
89 protocol: Protocol,
90 _input: &str,
91 _roles: &[Role],
92 ) -> Result<Protocol, ExtensionParseError> {
93 Ok(protocol)
94 }
95
96 pub fn can_handle_statement(&self, statement_type: &str) -> bool {
98 self.grammar_composer.has_extension_rule(statement_type)
99 }
100
101 pub fn get_composed_grammar(&mut self) -> Result<String, GrammarCompositionError> {
103 self.grammar_composer.compose()
104 }
105
106 pub fn extension_stats(&self) -> ExtensionStats {
108 ExtensionStats {
109 grammar_extensions: self.grammar_composer.extension_count(),
110 statement_parsers: 0,
112 }
113 }
114}
115
116impl Default for ExtensionParser {
117 fn default() -> Self {
118 Self::new()
119 }
120}
121
122#[derive(Debug, Clone)]
124pub struct ExtensionStats {
125 pub grammar_extensions: usize,
126 pub statement_parsers: usize,
127}
128
129#[derive(Debug, thiserror::Error)]
131pub enum ExtensionParseError {
132 #[error("Standard parsing failed: {0}")]
133 StandardParseError(#[from] ParseError),
134
135 #[error("Grammar composition failed: {0}")]
136 GrammarComposition(#[from] GrammarCompositionError),
137
138 #[error("Extension parsing failed: {0}")]
139 ExtensionParsing(String),
140
141 #[error("Unknown extension statement: {0}")]
142 UnknownExtension(String),
143}
144
145pub struct ExtensionParserBuilder {
147 parser: ExtensionParser,
148}
149
150impl ExtensionParserBuilder {
151 pub fn new() -> Self {
152 Self {
153 parser: ExtensionParser::new(),
154 }
155 }
156
157 pub fn with_extension<G, P>(
158 mut self,
159 grammar_ext: G,
160 statement_parser: P,
161 ) -> Result<Self, crate::extensions::ParseError>
162 where
163 G: crate::extensions::GrammarExtension + 'static,
164 P: StatementParser + 'static,
165 {
166 self.parser
167 .register_extension(grammar_ext, statement_parser)?;
168 Ok(self)
169 }
170
171 pub fn build(self) -> ExtensionParser {
172 self.parser
173 }
174}
175
176impl Default for ExtensionParserBuilder {
177 fn default() -> Self {
178 Self::new()
179 }
180}
181
182pub fn create_standard_extension_parser() -> ExtensionParser {
184 ExtensionParserBuilder::new()
185 .build()
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192 use crate::extensions::{GrammarExtension, ParseContext, StatementParser};
193
194 #[derive(Debug)]
195 struct TestGrammarExtension;
196
197 impl GrammarExtension for TestGrammarExtension {
198 fn grammar_rules(&self) -> &'static str {
199 "test_stmt = { \"test\" ~ ident }"
200 }
201
202 fn statement_rules(&self) -> Vec<&'static str> {
203 vec!["test_stmt"]
204 }
205
206 fn extension_id(&self) -> &'static str {
207 "test_extension"
208 }
209 }
210
211 #[derive(Debug)]
212 struct TestStatementParser;
213
214 impl StatementParser for TestStatementParser {
215 fn can_parse(&self, rule_name: &str) -> bool {
216 rule_name == "test_stmt"
217 }
218
219 fn supported_rules(&self) -> Vec<String> {
220 vec!["test_stmt".to_string()]
221 }
222
223 fn parse_statement(
224 &self,
225 _rule_name: &str,
226 _content: &str,
227 _context: &ParseContext,
228 ) -> Result<Box<dyn crate::extensions::ProtocolExtension>, crate::extensions::ParseError>
229 {
230 Err(crate::extensions::ParseError::Syntax {
232 message: "Test parser - not implemented".to_string(),
233 })
234 }
235 }
236
237 #[test]
238 fn test_extension_parser_creation() {
239 let parser = ExtensionParser::new();
240 let stats = parser.extension_stats();
241 assert_eq!(stats.grammar_extensions, 0);
242 }
243
244 #[test]
245 fn test_extension_registration() {
246 let mut parser = ExtensionParser::new();
247 parser
248 .register_extension(TestGrammarExtension, TestStatementParser)
249 .expect("extension should register");
250
251 let stats = parser.extension_stats();
252 assert_eq!(stats.grammar_extensions, 1);
253 assert!(parser.can_handle_statement("test_stmt"));
254 }
255
256 #[test]
257 fn test_builder_pattern() {
258 let parser = ExtensionParserBuilder::new()
259 .with_extension(TestGrammarExtension, TestStatementParser)
260 .expect("test extension should register")
261 .build();
262
263 assert!(parser.can_handle_statement("test_stmt"));
264 }
265
266 #[test]
267 fn test_standard_parsing() {
268 let mut parser = ExtensionParser::new();
269
270 let input = "protocol TestProtocol =\n roles Alice, Bob\n Alice -> Bob : Message\n";
271
272 let result = parser.parse_with_extensions(input);
273 assert!(result.is_ok(), "Should parse standard choreography");
274 }
275
276 #[test]
277 fn test_composed_grammar_generation() {
278 let mut parser = ExtensionParser::new();
279 parser
280 .register_extension(TestGrammarExtension, TestStatementParser)
281 .expect("extension should register");
282
283 let result = parser.get_composed_grammar();
284 assert!(result.is_ok(), "Should generate composed grammar");
285
286 let grammar = result.unwrap();
287 assert!(
288 grammar.contains("test_stmt"),
289 "Should contain extension rule"
290 );
291 assert!(
292 grammar.contains("choreography"),
293 "Should contain base rules"
294 );
295 }
296}