Skip to main content

lex_babel/
transforms.rs

1//! Transform integration for lex-babel formats
2//!
3//! This module provides transform-style interfaces for format conversions.
4//! While lex-parser provides the core transform infrastructure, lex-babel
5//! adds serialization transforms that operate on AST nodes.
6
7use crate::format::Format;
8use crate::formats::lex::formatting_rules::FormattingRules;
9use crate::formats::lex::LexFormat;
10use lex_core::lex::ast::Document;
11
12/// Serialize a Document to Lex format with default formatting rules
13///
14/// This provides a simple functional interface that can be used
15/// in transform-style pipelines outside the standard lex-parser transforms.
16///
17/// # Example
18///
19/// ```
20/// use lex_babel::transforms::serialize_to_lex;
21/// use lex_core::lex::transforms::standard::STRING_TO_AST;
22///
23/// let source = "Hello world\n";
24/// let doc = STRING_TO_AST.run(source.to_string()).unwrap();
25/// let formatted = serialize_to_lex(&doc).unwrap();
26/// assert_eq!(formatted, "Hello world\n");
27/// ```
28pub fn serialize_to_lex(doc: &Document) -> Result<String, String> {
29    let format = LexFormat::default();
30    format.serialize(doc).map_err(|e| e.to_string())
31}
32
33/// Serialize a Document to Lex format with custom formatting rules
34///
35/// # Example
36///
37/// ```
38/// use lex_babel::transforms::serialize_to_lex_with_rules;
39/// use lex_babel::formats::lex::formatting_rules::FormattingRules;
40/// use lex_core::lex::transforms::standard::STRING_TO_AST;
41///
42/// let source = "Hello world\n";
43/// let doc = STRING_TO_AST.run(source.to_string()).unwrap();
44///
45/// let mut rules = FormattingRules::default();
46/// rules.indent_string = "  ".to_string(); // 2-space indent
47///
48/// let formatted = serialize_to_lex_with_rules(&doc, rules).unwrap();
49/// ```
50pub fn serialize_to_lex_with_rules(
51    doc: &Document,
52    rules: FormattingRules,
53) -> Result<String, String> {
54    let format = LexFormat::new(rules);
55    format.serialize(doc).map_err(|e| e.to_string())
56}
57
58/// Round-trip transformation: parse and re-serialize
59///
60/// Useful for formatting operations and testing.
61///
62/// # Example
63///
64/// ```
65/// use lex_babel::transforms::format_lex_source;
66///
67/// let source = "Hello world\n";
68/// let formatted = format_lex_source(source).unwrap();
69/// assert_eq!(formatted, "Hello world\n");
70/// ```
71pub fn format_lex_source(source: &str) -> Result<String, String> {
72    use lex_core::lex::transforms::standard::STRING_TO_AST;
73
74    let doc = STRING_TO_AST
75        .run(source.to_string())
76        .map_err(|e| e.to_string())?;
77
78    serialize_to_lex(&doc)
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84    use lex_core::lex::ast::{ContentItem, Paragraph};
85
86    #[test]
87    fn test_serialize_to_lex() {
88        let doc = Document::with_content(vec![ContentItem::Paragraph(Paragraph::from_line(
89            "Test".to_string(),
90        ))]);
91
92        let result = serialize_to_lex(&doc);
93        assert!(result.is_ok());
94        assert_eq!(result.unwrap(), "Test\n");
95    }
96
97    #[test]
98    fn test_serialize_with_custom_rules() {
99        let doc = Document::with_content(vec![ContentItem::Paragraph(Paragraph::from_line(
100            "Test".to_string(),
101        ))]);
102
103        let rules = FormattingRules {
104            indent_string: "  ".to_string(),
105            ..Default::default()
106        };
107
108        let result = serialize_to_lex_with_rules(&doc, rules);
109        assert!(result.is_ok());
110    }
111
112    #[test]
113    fn test_format_lex_source() {
114        let source = "Hello world\n";
115        let formatted = format_lex_source(source);
116        assert!(formatted.is_ok());
117        assert_eq!(formatted.unwrap(), "Hello world\n");
118    }
119
120    #[test]
121    fn test_round_trip_simple() {
122        let original = "Introduction\n\n    This is a session.\n";
123        let formatted = format_lex_source(original).unwrap();
124
125        // Parse both and compare (structural equivalence)
126        use lex_core::lex::transforms::standard::STRING_TO_AST;
127
128        let doc1 = STRING_TO_AST.run(original.to_string()).unwrap();
129        let doc2 = STRING_TO_AST.run(formatted.clone()).unwrap();
130
131        // Both should parse successfully
132        assert_eq!(doc1.root.children.len(), doc2.root.children.len());
133    }
134}