use crate::Value;
use std::{
collections::HashMap,
fmt::{self, Display, Formatter},
};
#[derive(Debug, Clone, PartialEq)]
pub enum AST {
None,
Space,
Newline,
Statements(Vec<AST>),
Header(Box<AST>, u8),
Paragraph(Box<AST>),
Text(Vec<AST>),
String(String),
Bold(Box<AST>),
Italic(Box<AST>),
Underline(Box<AST>),
Strikethrough(Box<AST>),
Undercover(Box<AST>),
Code(String),
Raw(String),
MathInline(String),
MathDisplay(String),
Table {
head: Vec<AST>,
align: Vec<u8>,
terms: Vec<Vec<AST>>,
column: usize,
},
Quote {
body: Vec<AST>,
style: String,
},
Ordered(Vec<AST>),
Orderless(Vec<AST>),
Command(String, Vec<Value>, HashMap<String, Value>),
Escaped(String),
}
impl Display for AST {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
AST::None => write!(f, ""),
AST::Space => write!(f, " "),
AST::Newline => write!(f, "\n"),
AST::Header(a, l) => write!(f, "{} {}", "#".repeat(*l as usize), a),
AST::Statements(e) => {
let fs: Vec<String> = e.iter().map(|ast| format!("{}", ast)).collect();
write!(f, "{}", fs.join(""))
}
AST::Paragraph(t) => write!(f, "{}\n", t),
AST::Text(t) => {
let fs: Vec<String> = t.iter().map(|k| format!("{}", k)).collect();
write!(f, "{}", fs.join(""))
}
AST::Raw(s) => write!(f, "{}", s),
AST::Code(s) => write!(f, "`{}`", s),
AST::String(s) => write!(f, "{}", s),
AST::Italic(s) => write!(f, "*{}*", s),
AST::Bold(s) => write!(f, "**{}**", s),
AST::Underline(s) => write!(f, "~{}~", s),
AST::Strikethrough(s) => write!(f, "~~{}~~", s),
AST::Undercover(s) => write!(f, "~~~{}~~~", s),
AST::MathInline(s) => write!(f, "${}$", s),
AST::MathDisplay(s) => write!(f, "$${}$$", s),
AST::Quote { body, .. } => {
let s: Vec<_> = body.iter().map(|a| format!("> {}", a)).collect();
write!(f, "{}", s.join("\n"))
}
AST::Orderless(v) => {
let s: Vec<_> = v.iter().map(|a| format!("- {}", a)).collect();
write!(f, "{}", s.join("\n"))
}
AST::Command(s, args, kvs) => {
let a: Vec<String> = args.iter().map(|v| format!("{}", v)).collect();
let kv: Vec<String> = kvs.iter().map(|(k, v)| format!("{} = {}", k, v)).collect();
write!(f, "\\{}{{{}}}", s, [&a[..], &kv[..]].concat().join(", "))
}
_ => {
let a = format!("unimplemented AST::{:?}", self);
write!(f, "{}", a.split("(").next().unwrap_or("Unknown"))
}
}
}
}
impl From<&str> for AST {
fn from(s: &str) -> Self {
AST::String(s.to_string())
}
}
impl From<String> for AST {
fn from(s: String) -> Self {
AST::String(s)
}
}