use std::fmt;
use colored::*;
use crate::parser::error::EmptyError;
use crate::parser::warning::EmptyWarning;
#[derive(PartialEq, Eq, Clone)]
pub enum Ast {
Title {
level: u8,
content: Box<Ast>,
},
Bold(Box<Ast>),
Italic(Box<Ast>),
InlineMath(String),
Text(String),
Paragraph(Vec<Ast>),
Group(Vec<Ast>),
Newline,
Error(EmptyError),
Warning(EmptyWarning),
}
impl Ast {
pub fn errors(&self) -> Vec<EmptyError> {
let mut errors = vec![];
match self {
Ast::Error(e) => errors.push(e.clone()),
Ast::Warning(_) => {}
Ast::Group(children) => {
for child in children {
errors.extend(child.errors());
}
}
Ast::Paragraph(children) => {
for child in children {
errors.extend(child.errors());
}
}
Ast::Title { content: ast, .. } => {
errors.extend(ast.errors());
}
Ast::Bold(ast) => {
errors.extend(ast.errors());
}
Ast::Italic(ast) => {
errors.extend(ast.errors());
}
Ast::Text(_) | Ast::Newline | Ast::InlineMath(_) => (),
}
errors
}
pub fn warnings(&self) -> Vec<EmptyWarning> {
let mut warnings = vec![];
match self {
Ast::Warning(e) => warnings.push(e.clone()),
Ast::Error(_) => {}
Ast::Group(children) => {
for child in children {
warnings.extend(child.warnings());
}
}
Ast::Paragraph(children) => {
for child in children {
warnings.extend(child.warnings());
}
}
Ast::Title { content: ast, .. } => {
warnings.extend(ast.warnings());
}
Ast::Bold(ast) => {
warnings.extend(ast.warnings());
}
Ast::Italic(ast) => {
warnings.extend(ast.warnings());
}
Ast::Text(_) | Ast::Newline | Ast::InlineMath(_) => (),
}
warnings
}
pub fn print_debug(
&self,
fmt: &mut fmt::Formatter,
indent: &str,
last_child: bool,
) -> fmt::Result {
let delimiter1 = if indent == "" {
"─"
} else if last_child {
"â””"
} else {
"├"
};
let delimiter2 = match self {
Ast::Error(_) | Ast::Warning(_) | Ast::Text(_) | Ast::Newline | Ast::InlineMath(_) => {
"──"
}
_ => "─┬",
};
let new_indent = format!("{}{}{} ", indent, delimiter1, delimiter2);
let indent = if last_child {
format!("{} ", indent)
} else {
format!("{}│ ", indent)
};
match self {
Ast::Error(e) => writeln!(fmt, "{}{}", new_indent, &format!("Error({:?})", e).red())?,
Ast::Warning(e) => writeln!(
fmt,
"{}{}",
new_indent,
&format!("Warning({:?})", e).yellow()
)?,
Ast::Text(t) => writeln!(
fmt,
"{}{}{}{}",
new_indent,
"Text(".green(),
&format!("{:?}", t).dimmed(),
")".green()
)?,
Ast::Newline => writeln!(fmt, "{}NewLine", new_indent)?,
Ast::InlineMath(math) => writeln!(fmt, "{}Math({:?})", new_indent, math)?,
Ast::Group(children) => {
writeln!(fmt, "{}{}", new_indent, "Group".blue().bold())?;
let len = children.len();
for (index, child) in children.iter().enumerate() {
child.print_debug(fmt, &indent, index == len - 1)?;
}
}
Ast::Paragraph(children) => {
writeln!(fmt, "{}{}", new_indent, "Paragraph".blue().bold())?;
let len = children.len();
for (index, child) in children.iter().enumerate() {
child.print_debug(fmt, &indent, index == len - 1)?;
}
}
Ast::Title { content, level } => {
writeln!(
fmt,
"{}{}",
new_indent,
&format!("Title(level={})", level).magenta().bold()
)?;
content.print_debug(fmt, &indent, true)?;
}
Ast::Bold(ast) => {
writeln!(fmt, "{}{}", new_indent, "Bold".cyan().bold())?;
ast.print_debug(fmt, &indent, true)?;
}
Ast::Italic(ast) => {
writeln!(fmt, "{}{}", new_indent, "Italic".cyan().bold())?;
ast.print_debug(fmt, &indent, true)?;
}
}
Ok(())
}
}
impl fmt::Display for Ast {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Ast::Title { level, content } => {
for _ in 0..*level {
write!(fmt, "{}", "#".bold())?;
}
writeln!(fmt, "{}", &format!(" {}", content).bold())?;
}
Ast::Bold(subast) => write!(fmt, "{}", &format!("{}", subast).red())?,
Ast::Italic(subast) => write!(fmt, "{}", &format!("{}", subast).blue())?,
Ast::InlineMath(content) => write!(fmt, "${}$", content)?,
Ast::Text(content) => write!(fmt, "{}", content)?,
Ast::Group(children) => {
for child in children {
write!(fmt, "{}", child)?;
}
}
Ast::Paragraph(children) => {
for child in children {
write!(fmt, "{}", child)?;
}
}
Ast::Error(_) => writeln!(fmt, "?")?,
Ast::Newline => writeln!(fmt)?,
Ast::Warning(_) => (),
}
Ok(())
}
}
impl fmt::Debug for Ast {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.print_debug(fmt, "", true)
}
}