use std::fmt::*;
use crate::lexer::bareword_format;
pub trait FormatHtml {
fn to_html(&self) -> String {
let mut out = String::new();
FormatHtml::fmt(self, &mut out).unwrap();
out
}
fn fmt(&self, f: &mut String) -> std::fmt::Result;
fn space(f: &mut String) -> std::fmt::Result {
write!(f, " ")
}
fn tag_start(f: &mut String, tag: &str, class: &str) -> std::fmt::Result {
write!(f, "<{tag} class='{class}'>")
}
fn tag_end(f: &mut String, tag: &str) -> std::fmt::Result {
write!(f, "</{tag}>")
}
fn tag(
f: &mut String,
tag: &str,
class: &str,
inner: impl FnOnce(&mut String) -> std::fmt::Result
) -> std::fmt::Result {
Self::tag_start(f, tag, class)?;
inner(f)?;
Self::tag_end(f, tag)?;
Ok(())
}
fn ispan(
f: &mut String,
class: &str,
inner: impl FnOnce(&mut String) -> std::fmt::Result
) -> std::fmt::Result {
Self::tag_start(f, "span", class)?;
inner(f)?;
Self::tag_end(f, "span")?;
Ok(())
}
fn fspan(
f: &mut String,
class: &str,
inner: &impl FormatHtml
) -> std::fmt::Result {
Self::tag_start(f, "span", class)?;
FormatHtml::fmt(inner, f)?;
Self::tag_end(f, "span")?;
Ok(())
}
fn tspan(
f: &mut String,
class: &str,
inner: &str
) -> std::fmt::Result {
Self::tag_start(f, "span", class)?;
write!(f, "{inner}")?;
Self::tag_end(f, "span")?;
Ok(())
}
}
impl FormatHtml for super::Expression {
fn fmt(&self, f: &mut String) -> std::fmt::Result {
Self::ispan(f,
"expression",
|f| match self {
super::Expression::Empty => Self::tspan(f, "empty", "_"),
super::Expression::Value(v) => FormatHtml::fmt(v, f),
super::Expression::Invoke(i) => FormatHtml::fmt(i.as_ref(), f),
super::Expression::Field(e, i)
=> Self::ispan(f, "field", |f| {
Self::fspan(f, "target", e.as_ref())?;
Self::tspan(f, "separator", ".")?;
Self::tspan(f, "member", i)?;
Ok(())
}),
super::Expression::Index(e, i)
=> Self::ispan(f, "index", |f| {
Self::fspan(f, "target", e.as_ref())?;
Self::tspan(f, "separator", "[")?;
Self::fspan(f, "index", i.as_ref())?;
Self::tspan(f, "separator", "]")?;
Ok(())
}),
super::Expression::Range(s, e, inc)
=> Self::ispan(f, "range", |f| {
Self::fspan(f, "start", s.as_ref())?;
Self::tspan(f, "separator", "..")?;
if *inc {Self::tspan(f, "inclusive", "=")?;}
Self::fspan(f, "end", e.as_ref())?;
Ok(())
}),
super::Expression::Try(e, t) => Self::ispan(f, "try", |f| {
Self::fspan(f, "target", e.as_ref())?;
Self::tspan(f, "operator", "?")?;
if *t {Self::tspan(f, "operator", "!")?};
Ok(())
}),
super::Expression::Pipe(p) => FormatHtml::fmt(p.as_ref(), f),
}
)
}
}
impl FormatHtml for super::Literal {
fn fmt(&self, f: &mut String) -> std::fmt::Result {
match self {
crate::lexer::Literal::Nil => Self::tspan(f, "literal null", "null"),
crate::lexer::Literal::Bool(l) => Self::ispan(f, "literal bool", |f| write!(f, "{l:?}")),
crate::lexer::Literal::Int(l) => Self::ispan(f, "literal int", |f| write!(f, "{l:?}")),
crate::lexer::Literal::Dec(l) => Self::ispan(f, "literal dec", |f| write!(f, "{l:?}")),
crate::lexer::Literal::Uid(l) => Self::ispan(f, "literal uid", |f| write!(f, "U{l:?}")),
crate::lexer::Literal::Str(l) => Self::tspan(f, "literal str", &bareword_format(l)),
crate::lexer::Literal::Byt(_l) => Self::ispan(f, "literal byt", |f| write!(f, "BINARY-DATA")),
crate::lexer::Literal::RefRes => Self::tspan(f, "literal ref-res", "$"),
crate::lexer::Literal::RefCtx => Self::tspan(f, "literal ref-ctx", "$$"),
crate::lexer::Literal::RefVar(l) => Self::ispan(f, "literal ref-var", |f| write!(f, "${}", bareword_format(l))),
crate::lexer::Literal::ObjIdx(l) => Self::ispan(f, "literal obj-idx", |f| write!(f, "@{l:?}")),
crate::lexer::Literal::ObjUid(l) => Self::ispan(f, "literal obj-uid", |f| write!(f, "@{l:?}")),
crate::lexer::Literal::ObjKey(l) => Self::ispan(f, "literal obj-key", |f| write!(f, "@{}", bareword_format(l))),
}
}
}
impl FormatHtml for super::Invoke {
fn fmt(&self, f: &mut String) -> std::fmt::Result {
Self::ispan(f, "invoke", |f| {
Self::tspan(f, "name", &bareword_format(&self.name))?;
for arg in &self.pos_args {
Self::space(f)?;
Self::fspan(f, "val", arg)?;
}
for (key, arg) in &self.nom_args {
Self::space(f)?;
Self::ispan(f, "key-val", |f| {
Self::tspan(f, "key", &bareword_format(key))?;
Self::tspan(f, "separator", "=")?;
Self::fspan(f, "val", arg)?;
Ok(())
})?;
}
Ok(())
})
}
}
impl FormatHtml for super::Pipe {
fn fmt(&self, f: &mut String) -> std::fmt::Result {
Self::ispan(f, "pipe", |f| {
Self::fspan(f, "source", &self.source)?;
for seg in &self.stages {
Self::space(f)?;
Self::tspan(f, "separator", "|")?;
if seg.filter {
Self::tspan(f, "filter", "?")?;
}
Self::space(f)?;
Self::fspan(f, "segment", &seg.invoke)?;
}
Ok(())
})
}
}