use crate::ast::{Protocol, Role};
use crate::compiler::grammar::{GrammarComposer, GrammarCompositionError};
use crate::compiler::parser::{parse_choreography_str, ParseError};
use crate::extensions::StatementParser;
pub struct ExtensionParser {
grammar_composer: GrammarComposer,
parse_buffer: String,
annotation_cache: std::collections::HashMap<String, String>,
}
impl ExtensionParser {
pub fn new() -> Self {
Self {
grammar_composer: GrammarComposer::new(),
parse_buffer: String::with_capacity(1024), annotation_cache: std::collections::HashMap::with_capacity(16), }
}
pub fn register_extension<G, P>(
&mut self,
grammar_ext: G,
_statement_parser: P,
) -> Result<(), crate::extensions::ParseError>
where
G: crate::extensions::GrammarExtension + 'static,
P: StatementParser + 'static,
{
self.grammar_composer.register_extension(grammar_ext)?;
Ok(())
}
pub fn parse_with_extensions(
&mut self,
input: &str,
) -> Result<crate::ast::Choreography, ExtensionParseError> {
self.parse_buffer.clear();
self.annotation_cache.clear();
self.parse_buffer.reserve(input.len());
let mut choreography =
parse_choreography_str(input).map_err(ExtensionParseError::StandardParseError)?;
choreography.protocol =
self.process_extensions_optimized(choreography.protocol, input, &choreography.roles)?;
Ok(choreography)
}
fn process_extensions_optimized(
&mut self,
protocol: Protocol,
_input: &str,
_roles: &[Role],
) -> Result<Protocol, ExtensionParseError> {
Ok(protocol)
}
pub fn can_handle_statement(&self, statement_type: &str) -> bool {
self.grammar_composer.has_extension_rule(statement_type)
}
pub fn get_composed_grammar(&mut self) -> Result<String, GrammarCompositionError> {
self.grammar_composer.compose()
}
pub fn extension_stats(&self) -> ExtensionStats {
ExtensionStats {
grammar_extensions: self.grammar_composer.extension_count(),
statement_parsers: 0,
}
}
}
impl Default for ExtensionParser {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct ExtensionStats {
pub grammar_extensions: usize,
pub statement_parsers: usize,
}
#[derive(Debug, thiserror::Error)]
pub enum ExtensionParseError {
#[error("Standard parsing failed: {0}")]
StandardParseError(#[from] ParseError),
#[error("Grammar composition failed: {0}")]
GrammarComposition(#[from] GrammarCompositionError),
#[error("Extension parsing failed: {0}")]
ExtensionParsing(String),
#[error("Unknown extension statement: {0}")]
UnknownExtension(String),
}
pub struct ExtensionParserBuilder {
parser: ExtensionParser,
}
impl ExtensionParserBuilder {
pub fn new() -> Self {
Self {
parser: ExtensionParser::new(),
}
}
pub fn with_extension<G, P>(
mut self,
grammar_ext: G,
statement_parser: P,
) -> Result<Self, crate::extensions::ParseError>
where
G: crate::extensions::GrammarExtension + 'static,
P: StatementParser + 'static,
{
self.parser
.register_extension(grammar_ext, statement_parser)?;
Ok(self)
}
pub fn build(self) -> ExtensionParser {
self.parser
}
}
impl Default for ExtensionParserBuilder {
fn default() -> Self {
Self::new()
}
}
pub fn create_standard_extension_parser() -> ExtensionParser {
ExtensionParserBuilder::new()
.build()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::extensions::{GrammarExtension, ParseContext, StatementParser};
#[derive(Debug)]
struct TestGrammarExtension;
impl GrammarExtension for TestGrammarExtension {
fn grammar_rules(&self) -> &'static str {
"test_stmt = { \"test\" ~ ident }"
}
fn statement_rules(&self) -> Vec<&'static str> {
vec!["test_stmt"]
}
fn extension_id(&self) -> &'static str {
"test_extension"
}
}
#[derive(Debug)]
struct TestStatementParser;
impl StatementParser for TestStatementParser {
fn can_parse(&self, rule_name: &str) -> bool {
rule_name == "test_stmt"
}
fn supported_rules(&self) -> Vec<String> {
vec!["test_stmt".to_string()]
}
fn parse_statement(
&self,
_rule_name: &str,
_content: &str,
_context: &ParseContext,
) -> Result<Box<dyn crate::extensions::ProtocolExtension>, crate::extensions::ParseError>
{
Err(crate::extensions::ParseError::Syntax {
message: "Test parser - not implemented".to_string(),
})
}
}
#[test]
fn test_extension_parser_creation() {
let parser = ExtensionParser::new();
let stats = parser.extension_stats();
assert_eq!(stats.grammar_extensions, 0);
}
#[test]
fn test_extension_registration() {
let mut parser = ExtensionParser::new();
parser
.register_extension(TestGrammarExtension, TestStatementParser)
.expect("extension should register");
let stats = parser.extension_stats();
assert_eq!(stats.grammar_extensions, 1);
assert!(parser.can_handle_statement("test_stmt"));
}
#[test]
fn test_builder_pattern() {
let parser = ExtensionParserBuilder::new()
.with_extension(TestGrammarExtension, TestStatementParser)
.expect("test extension should register")
.build();
assert!(parser.can_handle_statement("test_stmt"));
}
#[test]
fn test_standard_parsing() {
let mut parser = ExtensionParser::new();
let input = "protocol TestProtocol =\n roles Alice, Bob\n Alice -> Bob : Message\n";
let result = parser.parse_with_extensions(input);
assert!(result.is_ok(), "Should parse standard choreography");
}
#[test]
fn test_composed_grammar_generation() {
let mut parser = ExtensionParser::new();
parser
.register_extension(TestGrammarExtension, TestStatementParser)
.expect("extension should register");
let result = parser.get_composed_grammar();
assert!(result.is_ok(), "Should generate composed grammar");
let grammar = result.unwrap();
assert!(
grammar.contains("test_stmt"),
"Should contain extension rule"
);
assert!(
grammar.contains("choreography"),
"Should contain base rules"
);
}
}