Make debug printing prettier

This commit is contained in:
Ayaz Hafiz 2022-06-15 22:04:41 -04:00
parent 74d498d762
commit c94c02ae3d
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
2 changed files with 117 additions and 60 deletions

View file

@ -431,7 +431,7 @@ fn empty_record() {
"{} -> Encoder fmt | fmt has EncoderFormatting", "{} -> Encoder fmt | fmt has EncoderFormatting",
indoc!( indoc!(
r#" r#"
\Test.0 -> (Encode.record [ ]) \Test.0 -> Encode.record []
"# "#
), ),
) )
@ -444,7 +444,7 @@ fn zero_field_record() {
"{} -> Encoder fmt | fmt has EncoderFormatting", "{} -> Encoder fmt | fmt has EncoderFormatting",
indoc!( indoc!(
r#" r#"
\Test.0 -> (Encode.record [ ]) \Test.0 -> Encode.record []
"# "#
), ),
) )
@ -457,8 +457,7 @@ fn one_field_record() {
"{ a : val } -> Encoder fmt | fmt has EncoderFormatting, val has Encoding", "{ a : val } -> Encoder fmt | fmt has EncoderFormatting, val has Encoding",
indoc!( indoc!(
r#" r#"
\Test.0 -> \Test.0 -> Encode.record [{ value: Encode.toEncoder Test.0.a, key: "a", }]
(Encode.record [ { value: (Encode.toEncoder (Test.0).a), key: "a", }, ])
"# "#
), ),
) )
@ -472,10 +471,10 @@ fn two_field_record() {
indoc!( indoc!(
r#" r#"
\Test.0 -> \Test.0 ->
(Encode.record [ Encode.record [
{ value: (Encode.toEncoder (Test.0).a), key: "a", }, { value: Encode.toEncoder Test.0.a, key: "a", },
{ value: (Encode.toEncoder (Test.0).b), key: "b", }, { value: Encode.toEncoder Test.0.b, key: "b", },
]) ]
"# "#
), ),
) )
@ -503,7 +502,7 @@ fn tag_one_label_zero_args() {
"[A] -> Encoder fmt | fmt has EncoderFormatting", "[A] -> Encoder fmt | fmt has EncoderFormatting",
indoc!( indoc!(
r#" r#"
\Test.0 -> when Test.0 is (A) -> (Encode.tag "A" [ ]) \Test.0 -> when Test.0 is A -> Encode.tag "A" []
"# "#
), ),
) )
@ -518,10 +517,8 @@ fn tag_one_label_two_args() {
r#" r#"
\Test.0 -> \Test.0 ->
when Test.0 is when Test.0 is
(ATest.1 Test.2) -> (Encode.tag "A" [ A Test.1 Test.2 ->
(Encode.toEncoder Test.1), Encode.tag "A" [Encode.toEncoder Test.1, Encode.toEncoder Test.2]
(Encode.toEncoder Test.2),
])
"# "#
), ),
) )
@ -530,17 +527,19 @@ fn tag_one_label_two_args() {
#[test] #[test]
fn tag_two_labels() { fn tag_two_labels() {
derive_test( derive_test(
v!([A v!(U8) v!(STR), B v!(STR)]), v!([A v!(U8) v!(STR) v!(U16), B v!(STR)]),
"[A val a, B b] -> Encoder fmt | a has Encoding, b has Encoding, fmt has EncoderFormatting, val has Encoding", "[A val a b, B c] -> Encoder fmt | a has Encoding, b has Encoding, c has Encoding, fmt has EncoderFormatting, val has Encoding",
indoc!( indoc!(
r#" r#"
\Test.0 -> \Test.0 ->
when Test.0 is when Test.0 is
(ATest.1 Test.2) -> (Encode.tag "A" [ A Test.1 Test.2 Test.3 ->
(Encode.toEncoder Test.1), Encode.tag "A" [
(Encode.toEncoder Test.2), Encode.toEncoder Test.1,
]) Encode.toEncoder Test.2,
(BTest.3) -> (Encode.tag "B" [ (Encode.toEncoder Test.3), ]) Encode.toEncoder Test.3,
]
B Test.4 -> Encode.tag "B" [Encode.toEncoder Test.4]
"# "#
), ),
) )

View file

@ -13,10 +13,31 @@ pub struct Ctx<'a> {
pub fn pretty_print(c: &Ctx, e: &Expr) -> String { pub fn pretty_print(c: &Ctx, e: &Expr) -> String {
let f = Arena::new(); let f = Arena::new();
expr(c, &f, e).append(f.hardline()).1.pretty(80).to_string() expr(c, EPrec::Free, &f, e)
.append(f.hardline())
.1
.pretty(80)
.to_string()
} }
fn expr<'a>(c: &Ctx, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a, Arena<'a>> { macro_rules! maybe_paren {
($paren_if_above:expr, $my_prec:expr, $doc:expr) => {
if $my_prec > $paren_if_above {
$doc.parens().group()
} else {
$doc
}
};
}
#[derive(PartialEq, PartialOrd)]
enum EPrec {
Free,
CallArg,
}
fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a, Arena<'a>> {
use EPrec::*;
match e { match e {
Num(_, n, _, _) | Int(_, _, n, _, _) | Float(_, _, n, _, _) => f.text(&**n), Num(_, n, _, _) | Int(_, _, n, _, _) | Float(_, _, n, _, _) => f.text(&**n),
Str(s) => f.text(format!(r#""{}""#, s)), Str(s) => f.text(format!(r#""{}""#, s)),
@ -28,15 +49,26 @@ fn expr<'a>(c: &Ctx, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a, Arena<'a>>
.reflow("[") .reflow("[")
.append( .append(
f.concat(loc_elems.iter().map(|le| { f.concat(loc_elems.iter().map(|le| {
let elem = expr(c, f, &le.value); f.hardline()
f.line().append(elem).append(",") .append(expr(c, Free, f, &le.value))
.append(f.text(","))
})) }))
.group() .group()
.nest(2), .nest(2),
) )
.append(f.line()) .append(f.line_())
.append("]")
.group()
.flat_alt(
f.reflow("[")
.append(f.intersperse(
loc_elems.iter().map(|le| expr(c, Free, f, &le.value)),
f.reflow(", "),
))
.append(f.line_())
.append("]") .append("]")
.group(), .group(),
),
Var(sym) | AbilityMember(sym, _, _) => f.text(format!( Var(sym) | AbilityMember(sym, _, _) => f.text(format!(
"{}.{}", "{}.{}",
sym.module_string(c.interns), sym.module_string(c.interns),
@ -46,11 +78,10 @@ fn expr<'a>(c: &Ctx, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a, Arena<'a>>
loc_cond, branches, .. loc_cond, branches, ..
} => f } => f
.reflow("when ") .reflow("when ")
.append(expr(c, f, &loc_cond.value)) .append(expr(c, Free, f, &loc_cond.value))
.append(f.text(" is")) .append(f.text(" is"))
.append( .append(
f.concat(branches.iter().map(|b| f.line().append(branch(c, f, b)))) f.concat(branches.iter().map(|b| f.line().append(branch(c, f, b))))
.nest(2)
.group(), .group(),
) )
.nest(2) .nest(2)
@ -63,13 +94,13 @@ fn expr<'a>(c: &Ctx, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a, Arena<'a>>
.concat(branches.iter().enumerate().map(|(i, (cond, body))| { .concat(branches.iter().enumerate().map(|(i, (cond, body))| {
let head = if i == 0 { "if " } else { "else if " }; let head = if i == 0 { "if " } else { "else if " };
(f.reflow(head) (f.reflow(head)
.append(expr(c, f, &cond.value)) .append(expr(c, Free, f, &cond.value))
.group() .group()
.nest(2)) .nest(2))
.append(f.line()) .append(f.line())
.append( .append(
f.reflow("then") f.reflow("then")
.append(f.softline().append(expr(c, f, &body.value))) .append(f.softline().append(expr(c, Free, f, &body.value)))
.group() .group()
.nest(2), .nest(2),
) )
@ -77,7 +108,7 @@ fn expr<'a>(c: &Ctx, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a, Arena<'a>>
})) }))
.append( .append(
f.reflow("else ") f.reflow("else ")
.append(expr(c, f, &final_else.value)) .append(expr(c, Free, f, &final_else.value))
.group() .group()
.nest(2), .nest(2),
) )
@ -86,12 +117,17 @@ fn expr<'a>(c: &Ctx, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a, Arena<'a>>
LetNonRec(_, _) => todo!(), LetNonRec(_, _) => todo!(),
Call(fun, args, _) => { Call(fun, args, _) => {
let (_, fun, _, _) = &**fun; let (_, fun, _, _) = &**fun;
f.text("(") maybe_paren!(
.append(expr(c, f, &fun.value)) Free,
p,
expr(c, CallArg, f, &fun.value)
.append(f.softline()) .append(f.softline())
.append(f.intersperse(args.iter().map(|le| expr(c, f, &le.1.value)), f.softline())) .append(f.intersperse(
.append(f.text(")")) args.iter().map(|le| expr(c, CallArg, f, &le.1.value)),
f.softline()
))
.group() .group()
)
} }
RunLowLevel { .. } => todo!(), RunLowLevel { .. } => todo!(),
ForeignCall { .. } => todo!(), ForeignCall { .. } => todo!(),
@ -105,13 +141,13 @@ fn expr<'a>(c: &Ctx, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a, Arena<'a>>
f.intersperse( f.intersperse(
arguments arguments
.iter() .iter()
.map(|(_, _, arg)| pattern(c, f, &arg.value)), .map(|(_, _, arg)| pattern(c, PPrec::Free, f, &arg.value)),
f.text(", "), f.text(", "),
), ),
) )
.append(f.text(" ->")) .append(f.text(" ->"))
.append(f.line()) .append(f.line())
.append(expr(c, f, &loc_body.value)) .append(expr(c, Free, f, &loc_body.value))
.nest(2) .nest(2)
.group(), .group(),
Record { fields, .. } => f Record { fields, .. } => f
@ -121,7 +157,7 @@ fn expr<'a>(c: &Ctx, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a, Arena<'a>>
let field = f let field = f
.text(name.as_str()) .text(name.as_str())
.append(f.reflow(": ")) .append(f.reflow(": "))
.append(expr(c, f, &field.loc_expr.value)) .append(expr(c, Free, f, &field.loc_expr.value))
.nest(2) .nest(2)
.group(); .group();
f.line().append(field).append(",") f.line().append(field).append(",")
@ -135,10 +171,7 @@ fn expr<'a>(c: &Ctx, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a, Arena<'a>>
EmptyRecord => f.text("{}"), EmptyRecord => f.text("{}"),
Access { Access {
loc_expr, field, .. loc_expr, field, ..
} => f } => expr(c, CallArg, f, &loc_expr.value)
.text("(")
.append(expr(c, f, &loc_expr.value))
.append(f.text(")"))
.append(f.text(format!(".{}", field.as_str()))) .append(f.text(format!(".{}", field.as_str())))
.group(), .group(),
Accessor(_) => todo!(), Accessor(_) => todo!(),
@ -161,21 +194,35 @@ fn branch<'a>(c: &Ctx, f: &'a Arena<'a>, b: &'a WhenBranch) -> DocBuilder<'a, Ar
} = b; } = b;
f.intersperse( f.intersperse(
patterns.iter().map(|lp| pattern(c, f, &lp.value)), patterns
.iter()
.map(|lp| pattern(c, PPrec::Free, f, &lp.value)),
f.text(" | "), f.text(" | "),
) )
.append(match guard { .append(match guard {
Some(e) => f.text("if ").append(expr(c, f, &e.value)), Some(e) => f.text("if ").append(expr(c, EPrec::Free, f, &e.value)),
None => f.nil(), None => f.nil(),
}) })
.append(f.text(" ->")) .append(f.text(" ->"))
.append(f.softline()) .append(f.line())
.append(expr(c, f, &value.value)) .append(expr(c, EPrec::Free, f, &value.value))
.nest(2) .nest(2)
.group() .group()
} }
fn pattern<'a>(c: &Ctx, f: &'a Arena<'a>, p: &'a Pattern) -> DocBuilder<'a, Arena<'a>> { #[derive(PartialEq, PartialOrd)]
enum PPrec {
Free,
AppArg,
}
fn pattern<'a>(
c: &Ctx,
prec: PPrec,
f: &'a Arena<'a>,
p: &'a Pattern,
) -> DocBuilder<'a, Arena<'a>> {
use PPrec::*;
use Pattern::*; use Pattern::*;
match p { match p {
Identifier(sym) Identifier(sym)
@ -190,19 +237,30 @@ fn pattern<'a>(c: &Ctx, f: &'a Arena<'a>, p: &'a Pattern) -> DocBuilder<'a, Aren
tag_name, tag_name,
arguments, arguments,
.. ..
} => f } => maybe_paren!(
.text(format!("({}", tag_name.0.as_str())) Free,
.append(f.intersperse( prec,
arguments.iter().map(|(_, lp)| pattern(c, f, &lp.value)), f.text(tag_name.0.as_str())
.append(if arguments.is_empty() {
f.nil()
} else {
f.space()
})
.append(
f.intersperse(
arguments
.iter()
.map(|(_, lp)| pattern(c, AppArg, f, &lp.value)),
f.space(), f.space(),
)) )
.append(")") )
.group(), .group()
),
UnwrappedOpaque { UnwrappedOpaque {
opaque, argument, .. opaque, argument, ..
} => f } => f
.text(format!("@{} ", opaque.module_string(c.interns))) .text(format!("@{} ", opaque.module_string(c.interns)))
.append(pattern(c, f, &argument.1.value)) .append(pattern(c, Free, f, &argument.1.value))
.group(), .group(),
RecordDestructure { destructs, .. } => f RecordDestructure { destructs, .. } => f
.text("{") .text("{")
@ -214,11 +272,11 @@ fn pattern<'a>(c: &Ctx, f: &'a Arena<'a>, p: &'a Pattern) -> DocBuilder<'a, Aren
roc_can::pattern::DestructType::Optional(_, e) => f roc_can::pattern::DestructType::Optional(_, e) => f
.text(label.as_str()) .text(label.as_str())
.append(f.text(" ? ")) .append(f.text(" ? "))
.append(expr(c, f, &e.value)), .append(expr(c, EPrec::Free, f, &e.value)),
roc_can::pattern::DestructType::Guard(_, p) => f roc_can::pattern::DestructType::Guard(_, p) => f
.text(label.as_str()) .text(label.as_str())
.append(f.text(": ")) .append(f.text(": "))
.append(pattern(c, f, &p.value)), .append(pattern(c, Free, f, &p.value)),
}, },
), ),
f.text(", "), f.text(", "),