1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
use crate::parse::tokens::Site;
use std::{convert, fmt, error::Error};

use colored::*;

/// Error type for specific errors with generating
/// each type of markup.
#[derive(Debug, Clone)]
pub struct GenerationError {
    pub markup : String,
    pub message : String,
    pub site : Site
}

impl GenerationError {
    /// Create a new error given the ML, the message, and the site.
    pub fn new(ml : &str, msg : &str, site : &Site) -> Self {
        Self {
            markup: ml.to_owned(),
            message: msg.to_owned(),
            site: site.to_owned()
        }
    }
    /// When an error cannot be given a location,
    /// or exact point of failure.
    pub fn unknown(ml : &str) -> Self {
        Self {
            markup: ml.to_owned(),
            message: String::from("Unknown generation error (bug)."),
            site: Site::fake()
        }
    }
}

/// Implement fmt::Display for user-facing error output.
impl fmt::Display for GenerationError {
    fn fmt(&self, f : &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}: {}",
            format!("[{}] Error Generating {} {}",
                "**".red().bold(),
                self.markup.bold(), self.site).white(),
            self.message)
    }
}

/// Implements std::error::Error.
impl Error for GenerationError { }

/// An fmt::Error can be cast to an equally horribly
/// ambiguous GenerationError.
impl convert::From<fmt::Error> for GenerationError {
    fn from(_ : fmt::Error) -> Self {
        Self {
            markup: String::from("Unknown"),
            message: String::from(
                "Unknown error while writing to format buffer"),
            site: Site::fake()
        }
    }
}

pub type Formatter<'a> = &'a mut dyn fmt::Write;

/// Trait for all structs that can generate specific markup
/// for the s-expression tree.
pub trait MarkupDisplay {
    // Required definitions:
    /// Similar to fmt in Display/Debug traits, takes in a
    /// mutable writable buffer, returns success or a specifc
    /// error while generating the markup.
    fn generate(&self, buf : Formatter)
        -> Result<(), GenerationError>;
    /// Documentises the input, that's to say, it adds any
    /// extra meta-information to the generated markup, if
    /// the s-expressions your wrote ommited it.
    /// e.g. All XML gets a `<?xml ... ?>` tag added to it.
    fn document(&self) -> Result<String, GenerationError>;
    // Default definitions:
    /// Directly converts the s-expressions into a string
    /// containing the markup, unless there was an error.
    fn display(&self) -> Result<String, GenerationError> {
        let mut buf = String::new();
        self.generate(&mut buf)?;
        Ok(buf)
    }
}

/// Automatically implement fmt::Display as a wrapper around
/// MarkupDisplay::generate, but throws away the useful error message.
impl fmt::Display for dyn MarkupDisplay {
    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
        self.generate(f).map_err(|_| fmt::Error)
    }
}
/// XML generation.
pub mod xml;

/// HTML5 CSS generation.
pub mod css;
/// HTML5 HTML generation.
pub mod html;