lex-babel 0.8.2

Format conversion library for the lex format
Documentation
//! Lex format implementation
//!
//! This module implements the Format trait for Lex itself, treating Lex
//! as just another format in the system. This creates a uniform API where
//! Lex can be converted to/from other formats using the same interface.

use crate::error::FormatError;
use crate::format::Format;
use lex_core::lex::ast::Document;
use lex_core::lex::transforms::standard::STRING_TO_AST;

pub mod formatting_rules;
pub mod serializer;

use formatting_rules::FormattingRules;
use serializer::LexSerializer;
///
/// Parses Lex source text into a Document AST by delegating to lex-parser.
/// Serialization is implemented via LexSerializer.
#[derive(Default)]
pub struct LexFormat {
    rules: FormattingRules,
}

impl LexFormat {
    pub fn new(rules: FormattingRules) -> Self {
        Self { rules }
    }
}

impl Format for LexFormat {
    fn name(&self) -> &str {
        "lex"
    }

    fn description(&self) -> &str {
        "Lex document format"
    }

    fn file_extensions(&self) -> &[&str] {
        &["lex"]
    }

    fn supports_parsing(&self) -> bool {
        true
    }

    fn supports_serialization(&self) -> bool {
        true
    }

    fn parse(&self, source: &str) -> Result<Document, FormatError> {
        STRING_TO_AST
            .run(source.to_string())
            .map_err(|e| FormatError::ParseError(e.to_string()))
    }

    fn serialize(&self, doc: &Document) -> Result<String, FormatError> {
        let serializer = LexSerializer::new(self.rules.clone());
        serializer
            .serialize(doc)
            .map_err(FormatError::SerializationError)
    }
}

/// Convenience function to export a Document AST into a Lex string
/// using the default formatting rules.
pub fn export(doc: &Document) -> Result<String, FormatError> {
    LexFormat::default().serialize(doc)
}

#[cfg(test)]
mod tests {
    use super::*;
    use lex_core::lex::ast::{ContentItem, Paragraph};

    #[test]
    fn test_lex_format_name() {
        let format = LexFormat::default();
        assert_eq!(format.name(), "lex");
    }

    #[test]
    fn test_lex_format_supports_parsing() {
        let format = LexFormat::default();
        assert!(format.supports_parsing());
        assert!(format.supports_serialization());
    }

    #[test]
    fn test_lex_format_parse_simple() {
        let format = LexFormat::default();
        let source = "Hello world\n";

        let result = format.parse(source);
        assert!(result.is_ok());

        let doc = result.unwrap();
        assert_eq!(doc.root.children.len(), 1);

        match &doc.root.children[0] {
            ContentItem::Paragraph(_) => {}
            _ => panic!("Expected paragraph"),
        }
    }

    #[test]
    fn test_lex_format_parse_session() {
        let format = LexFormat::default();
        let source = "Introduction:\n    Welcome to the guide\n";

        let result = format.parse(source);
        assert!(result.is_ok());

        let doc = result.unwrap();
        // Just verify that something was parsed successfully
        // The exact structure depends on the parser implementation
        assert!(!doc.root.children.is_empty());
    }

    #[test]
    fn test_lex_format_parse_error() {
        let format = LexFormat::default();
        // Create invalid Lex that would cause a parse error
        // Note: Current parser is very permissive, so this might not fail
        // But the test shows the error handling works
        let source = "";

        let result = format.parse(source);
        // Empty document should parse successfully
        assert!(result.is_ok());
    }

    #[test]
    fn test_lex_format_serialize_supported() {
        let format = LexFormat::default();
        let doc = Document::with_content(vec![ContentItem::Paragraph(Paragraph::from_line(
            "Test".to_string(),
        ))]);

        let result = format.serialize(&doc);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), "Test\n");
    }
}