use super::{
Dump, NUMBER_COLOR, STRING_CONTENT_COLOR, STRING_QUOTE_COLOR, Writer, dump_list, escape_string,
sub_expr, with_brackets,
};
use crate::ast::{
Annotated, Binder, Expression, Item, ParamAttr, ParamDefault, Parameter, Selector, SetDefault,
SimpleSelector, Span, StringPart, Term, Token, Trailed, TrailingComment, Trivia, TriviaPiece,
};
use crate::dump_enum;
use crate::format_constructor;
use crate::format_record;
macro_rules! simple_atom {
($ty:ty, |$self_:ident, $w:ident| $body:expr) => {
impl Dump for $ty {
fn dump<W: Writer>(&self, $w: &mut W) {
let $self_ = self;
$body
}
fn is_simple(&self) -> bool {
true
}
fn is_atomic(&self) -> bool {
true
}
}
};
}
simple_atom!(&str, |s, w| {
w.write_colored("\"", STRING_QUOTE_COLOR);
w.write_colored(&escape_string(s), STRING_CONTENT_COLOR);
w.write_colored("\"", STRING_QUOTE_COLOR);
});
simple_atom!(String, |s, w| s.as_str().dump(w));
simple_atom!(Box<str>, |s, w| (&**s).dump(w));
simple_atom!(isize, |n, w| w.write_colored(&n.to_string(), NUMBER_COLOR));
simple_atom!(usize, |n, w| w.write_colored(&n.to_string(), NUMBER_COLOR));
simple_atom!(bool, |b, w| w.write_plain(if *b {
"True"
} else {
"False"
}));
impl Dump for Trailed<Expression> {
fn dump<W: Writer>(&self, w: &mut W) {
self.value.dump(w);
w.newline(); }
}
impl Dump for Expression {
fn dump<W: Writer>(&self, w: &mut W) {
match self {
Self::Term(term) => format_constructor!(w, "Term", [term]),
Self::With {
kw_with,
scope,
semi,
body,
} => {
format_constructor!(w, "With", [kw_with, &**scope, semi, &**body]);
}
Self::Let {
kw_let,
bindings,
kw_in,
body,
} => {
format_constructor!(w, "Let", [kw_let, &bindings.0, kw_in, &**body]);
}
Self::Assert {
kw_assert,
cond,
semi,
body,
} => {
format_constructor!(w, "Assert", [kw_assert, &**cond, semi, &**body]);
}
Self::If {
kw_if,
cond,
kw_then,
then_branch,
kw_else,
else_branch,
} => {
format_constructor!(
w,
"If",
[
kw_if,
&**cond,
kw_then,
&**then_branch,
kw_else,
&**else_branch
]
);
}
Self::Lambda { param, colon, body } => {
format_constructor!(w, "Abstraction", [param, colon, &**body]);
}
Self::Apply { func, arg } => {
format_constructor!(w, "Application", [&**func, &**arg]);
}
Self::Operation { lhs, op, rhs } => {
format_constructor!(w, "Operation", [&**lhs, op, &**rhs]);
}
Self::HasAttr {
lhs,
question,
path,
} => {
format_constructor!(w, "MemberCheck", [&**lhs, question, path]);
}
Self::Negation { minus, expr } => {
format_constructor!(w, "Negation", [minus, &**expr]);
}
Self::Not { bang, expr } => {
format_constructor!(w, "Inversion", [bang, &**expr]);
}
}
}
}
impl Dump for Term {
fn dump<W: Writer>(&self, w: &mut W) {
match self {
Self::Token(leaf) => format_constructor!(w, "Token", [leaf]),
Self::SimpleString(s) => format_constructor!(w, "SimpleString", [s]),
Self::IndentedString(s) => format_constructor!(w, "IndentedString", [s]),
Self::Path(p) => format_constructor!(w, "Path", [p]),
Self::List { open, items, close } => {
format_constructor!(w, "List", [open, &items.0, close]);
}
Self::Set {
rec,
open,
items,
close,
} => {
format_constructor!(w, "Set", [rec, open, &items.0, close]);
}
Self::Selection {
base,
selectors,
default,
} => {
format_constructor!(w, "Selection", [&**base, selectors, default]);
}
Self::Parenthesized { open, expr, close } => {
format_constructor!(w, "Parenthesized", [open, &**expr, close]);
}
}
}
}
fn format_pair<W: Writer, A: Dump, B: Dump>(w: &mut W, a: &A, b: &B) {
with_brackets(w, "(", ")", true, |w, paren_color| {
w.write_plain(" ");
a.dump(w);
w.newline();
w.write_colored(",", paren_color);
w.write_plain(" ");
b.dump(w);
w.newline();
});
}
impl Dump for SetDefault {
fn dump<W: Writer>(&self, w: &mut W) {
format_pair(w, &self.or_kw, &*self.value);
}
fn has_delimiters(&self) -> bool {
true
}
}
impl Dump for ParamDefault {
fn dump<W: Writer>(&self, w: &mut W) {
format_pair(w, &self.question, &self.value);
}
fn has_delimiters(&self) -> bool {
true
}
}
impl<T: Dump> Dump for Item<T> {
fn dump<W: Writer>(&self, w: &mut W) {
match self {
Self::Item(inner) => {
format_constructor!(w, "Item", [inner]);
}
Self::Comments(trivia) => {
w.write_plain("Comments");
sub_expr(w, trivia);
}
}
}
fn is_simple(&self) -> bool {
match self {
Self::Item(_) => false,
Self::Comments(trivia) => trivia.is_simple(),
}
}
}
impl Dump for Binder {
fn dump<W: Writer>(&self, w: &mut W) {
match self {
Self::Inherit {
kw,
from,
attrs,
semi,
} => {
format_constructor!(w, "Inherit", [kw, from, attrs, semi]);
}
Self::Assignment {
path,
eq,
value,
semi,
} => {
format_constructor!(w, "Assignment", [path, eq, value, semi]);
}
}
}
}
impl Dump for Selector {
fn dump<W: Writer>(&self, w: &mut W) {
format_constructor!(w, "Selector", [&self.dot, &self.selector]);
}
}
impl Dump for SimpleSelector {
fn dump<W: Writer>(&self, w: &mut W) {
match self {
Self::ID(leaf) => {
format_constructor!(w, "IDSelector", [leaf]);
}
Self::Interpol(part) => {
format_constructor!(w, "InterpolSelector", [part]);
}
Self::String(string) => {
format_constructor!(w, "StringSelector", [string]);
}
}
}
}
impl Dump for TriviaPiece {
fn dump<W: Writer>(&self, w: &mut W) {
dump_enum!(self, w, {
EmptyLine => [],
LineComment(text) => [text],
BlockComment(is_doc, lines) => [is_doc, lines],
LanguageAnnotation(text) => [text],
});
}
fn is_simple(&self) -> bool {
match self {
Self::EmptyLine | Self::LineComment(_) | Self::LanguageAnnotation(_) => true,
Self::BlockComment(_is_doc, lines) => lines.is_simple(),
}
}
fn is_atomic(&self) -> bool {
matches!(self, Self::EmptyLine)
}
}
impl Dump for Trivia {
fn dump<W: Writer>(&self, w: &mut W) {
w.write_plain("fromList");
sub_expr::<[_], _>(w, self);
}
fn renders_inline_parens(&self) -> bool {
<[_] as Dump>::is_simple(self)
}
}
impl Dump for Parameter {
fn dump<W: Writer>(&self, w: &mut W) {
match self {
Self::Id(leaf) => {
format_constructor!(w, "IDParameter", [leaf]);
}
Self::Set { open, attrs, close } => {
format_constructor!(w, "SetParameter", [open, attrs, close]);
}
Self::Context { lhs, at, rhs } => {
format_constructor!(w, "ContextParameter", [&**lhs, at, &**rhs]);
}
}
}
}
impl Dump for ParamAttr {
fn dump<W: Writer>(&self, w: &mut W) {
match self {
Self::Attr {
name,
default,
comma,
} => {
format_constructor!(w, "ParamAttr", [name, default, comma]);
}
Self::Ellipsis(ellipsis) => {
format_constructor!(w, "ParamEllipsis", [ellipsis]);
}
}
}
}
impl Dump for StringPart {
fn dump<W: Writer>(&self, w: &mut W) {
match self {
Self::TextPart(text) => {
format_constructor!(w, "TextPart", [text]);
}
Self::Interpolation(whole) => {
w.write_plain("Interpolation");
w.write_plain(" ");
whole.value.dump(w);
}
}
}
fn is_simple(&self) -> bool {
match self {
Self::TextPart(_) => true,
Self::Interpolation(_) => false,
}
}
}
const fn token_haskell_name(t: &Token) -> Option<&'static str> {
macro_rules! map {
($($v:ident => $s:literal),* $(,)?) => {
match t { $(Token::$v => Some($s),)* _ => None }
};
}
map! {
Assert => "KAssert", Else => "KElse", If => "KIf", In => "KIn",
Inherit => "KInherit", Let => "KLet", OrDefault => "KOr", Rec => "KRec",
Then => "KThen", With => "KWith",
BraceOpen => "TBraceOpen", BraceClose => "TBraceClose",
BrackOpen => "TBrackOpen", BrackClose => "TBrackClose",
InterOpen => "TInterOpen", InterClose => "TInterClose",
ParenOpen => "TParenOpen", ParenClose => "TParenClose",
Assign => "TAssign", At => "TAt", Colon => "TColon", Comma => "TComma",
Dot => "TDot", DoubleQuote => "TDoubleQuote",
DoubleSingleQuote => "TDoubleSingleQuote", Ellipsis => "TEllipsis",
Question => "TQuestion", Semicolon => "TSemicolon",
Concat => "TConcat", Negate => "TNegate", Update => "TUpdate",
Plus => "TPlus", Minus => "TMinus", Mul => "TMul", Div => "TDiv",
And => "TAnd", Or => "TOr", Equal => "TEqual",
Greater => "TGreater", GreaterEqual => "TGreaterEqual",
Implies => "TImplies", Less => "TLess", LessEqual => "TLessEqual",
Not => "TNot", Unequal => "TUnequal",
PipeForward => "TPipeForward", PipeBackward => "TPipeBackward",
Tilde => "TTilde", Sof => "SOF",
}
}
impl Dump for Token {
fn dump<W: Writer>(&self, w: &mut W) {
dump_enum!(self, w, {
Integer(s) => [&s.as_str()],
Float(s) => [&s.as_str()],
Identifier(s) => [&s.as_str()],
EnvPath(s) => [&s.as_str()],
_ => {
w.write_plain(token_haskell_name(self).expect("data-carrying tokens handled above"));
}
});
}
fn is_simple(&self) -> bool {
true
}
}
#[derive(Debug)]
struct SpanWrapper(Span);
impl Dump for SpanWrapper {
fn dump<W: Writer>(&self, w: &mut W) {
use crate::error::ErrorContext;
w.write_plain("Pos ");
let ctx = ErrorContext::new(w.source(), None);
let pos = ctx.position(self.0.start());
pos.line.dump(w);
}
fn is_simple(&self) -> bool {
true
}
}
impl Dump for TrailingComment {
fn dump<W: Writer>(&self, w: &mut W) {
with_brackets(w, "(", ")", true, |w, _| {
w.write_plain(" ");
format_constructor!(w, "TrailingComment", [&&*self.0]);
w.write_plain(" ");
});
}
fn has_delimiters(&self) -> bool {
true
}
}
impl<T: Dump> Dump for Annotated<T> {
fn dump<W: Writer>(&self, w: &mut W) {
w.write_plain("Ann");
format_record!(
w,
[
("preTrivia", &self.pre_trivia),
("sourceLine", &SpanWrapper(self.span)),
("value", &self.value),
("trailComment", &self.trail_comment),
]
);
}
}
impl<T: Dump> Dump for [T] {
fn dump<W: Writer>(&self, w: &mut W) {
dump_list(w, self, true);
}
fn is_simple(&self) -> bool {
match self {
[] => true,
[item] => item.is_atomic() || (item.is_simple() && item.has_delimiters()),
_ => false,
}
}
fn has_delimiters(&self) -> bool {
true
}
fn is_empty(&self) -> bool {
<Self>::is_empty(self)
}
}
impl<T: Dump> Dump for Vec<T> {
fn dump<W: Writer>(&self, w: &mut W) {
<[T] as Dump>::dump(self, w);
}
fn is_simple(&self) -> bool {
<[T] as Dump>::is_simple(self)
}
fn has_delimiters(&self) -> bool {
true
}
fn is_empty(&self) -> bool {
<[T]>::is_empty(self)
}
}
impl<T: Dump> Dump for Option<T> {
fn dump<W: Writer>(&self, w: &mut W) {
match self {
Some(value) => {
format_constructor!(w, "Just", [value]);
}
None => {
w.write_plain("Nothing");
}
}
}
fn is_simple(&self) -> bool {
self.is_none()
}
}
impl<A: Dump, B: Dump> Dump for (A, B) {
fn dump<W: Writer>(&self, w: &mut W) {
format_pair(w, &self.0, &self.1);
}
fn has_delimiters(&self) -> bool {
true
}
}
impl<T: Dump> Dump for Box<[T]> {
fn dump<W: Writer>(&self, w: &mut W) {
<[T] as Dump>::dump(self, w);
}
fn is_simple(&self) -> bool {
<[T] as Dump>::is_simple(self)
}
fn has_delimiters(&self) -> bool {
true
}
fn is_empty(&self) -> bool {
<[T]>::is_empty(self)
}
}
impl<T: Dump> Dump for Box<T> {
fn dump<W: Writer>(&self, w: &mut W) {
(**self).dump(w);
}
fn is_simple(&self) -> bool {
(**self).is_simple()
}
}