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}