mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
Make debug printing prettier
This commit is contained in:
parent
74d498d762
commit
c94c02ae3d
2 changed files with 117 additions and 60 deletions
|
@ -431,7 +431,7 @@ fn empty_record() {
|
|||
"{} -> Encoder fmt | fmt has EncoderFormatting",
|
||||
indoc!(
|
||||
r#"
|
||||
\Test.0 -> (Encode.record [ ])
|
||||
\Test.0 -> Encode.record []
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
@ -444,7 +444,7 @@ fn zero_field_record() {
|
|||
"{} -> Encoder fmt | fmt has EncoderFormatting",
|
||||
indoc!(
|
||||
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",
|
||||
indoc!(
|
||||
r#"
|
||||
\Test.0 ->
|
||||
(Encode.record [ { value: (Encode.toEncoder (Test.0).a), key: "a", }, ])
|
||||
\Test.0 -> Encode.record [{ value: Encode.toEncoder Test.0.a, key: "a", }]
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
@ -472,10 +471,10 @@ fn two_field_record() {
|
|||
indoc!(
|
||||
r#"
|
||||
\Test.0 ->
|
||||
(Encode.record [
|
||||
{ value: (Encode.toEncoder (Test.0).a), key: "a", },
|
||||
{ value: (Encode.toEncoder (Test.0).b), key: "b", },
|
||||
])
|
||||
Encode.record [
|
||||
{ value: Encode.toEncoder Test.0.a, key: "a", },
|
||||
{ value: Encode.toEncoder Test.0.b, key: "b", },
|
||||
]
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
@ -503,7 +502,7 @@ fn tag_one_label_zero_args() {
|
|||
"[A] -> Encoder fmt | fmt has EncoderFormatting",
|
||||
indoc!(
|
||||
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#"
|
||||
\Test.0 ->
|
||||
when Test.0 is
|
||||
(ATest.1 Test.2) -> (Encode.tag "A" [
|
||||
(Encode.toEncoder Test.1),
|
||||
(Encode.toEncoder Test.2),
|
||||
])
|
||||
A Test.1 Test.2 ->
|
||||
Encode.tag "A" [Encode.toEncoder Test.1, Encode.toEncoder Test.2]
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
@ -530,17 +527,19 @@ fn tag_one_label_two_args() {
|
|||
#[test]
|
||||
fn tag_two_labels() {
|
||||
derive_test(
|
||||
v!([A v!(U8) v!(STR), B v!(STR)]),
|
||||
"[A val a, B b] -> Encoder fmt | a has Encoding, b has Encoding, fmt has EncoderFormatting, val has Encoding",
|
||||
v!([A v!(U8) v!(STR) v!(U16), B v!(STR)]),
|
||||
"[A val a b, B c] -> Encoder fmt | a has Encoding, b has Encoding, c has Encoding, fmt has EncoderFormatting, val has Encoding",
|
||||
indoc!(
|
||||
r#"
|
||||
\Test.0 ->
|
||||
when Test.0 is
|
||||
(ATest.1 Test.2) -> (Encode.tag "A" [
|
||||
(Encode.toEncoder Test.1),
|
||||
(Encode.toEncoder Test.2),
|
||||
])
|
||||
(BTest.3) -> (Encode.tag "B" [ (Encode.toEncoder Test.3), ])
|
||||
A Test.1 Test.2 Test.3 ->
|
||||
Encode.tag "A" [
|
||||
Encode.toEncoder Test.1,
|
||||
Encode.toEncoder Test.2,
|
||||
Encode.toEncoder Test.3,
|
||||
]
|
||||
B Test.4 -> Encode.tag "B" [Encode.toEncoder Test.4]
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
|
|
@ -13,10 +13,31 @@ pub struct Ctx<'a> {
|
|||
|
||||
pub fn pretty_print(c: &Ctx, e: &Expr) -> String {
|
||||
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 {
|
||||
Num(_, n, _, _) | Int(_, _, n, _, _) | Float(_, _, n, _, _) => f.text(&**n),
|
||||
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("[")
|
||||
.append(
|
||||
f.concat(loc_elems.iter().map(|le| {
|
||||
let elem = expr(c, f, &le.value);
|
||||
f.line().append(elem).append(",")
|
||||
f.hardline()
|
||||
.append(expr(c, Free, f, &le.value))
|
||||
.append(f.text(","))
|
||||
}))
|
||||
.group()
|
||||
.nest(2),
|
||||
)
|
||||
.append(f.line())
|
||||
.append(f.line_())
|
||||
.append("]")
|
||||
.group(),
|
||||
.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("]")
|
||||
.group(),
|
||||
),
|
||||
Var(sym) | AbilityMember(sym, _, _) => f.text(format!(
|
||||
"{}.{}",
|
||||
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, ..
|
||||
} => f
|
||||
.reflow("when ")
|
||||
.append(expr(c, f, &loc_cond.value))
|
||||
.append(expr(c, Free, f, &loc_cond.value))
|
||||
.append(f.text(" is"))
|
||||
.append(
|
||||
f.concat(branches.iter().map(|b| f.line().append(branch(c, f, b))))
|
||||
.nest(2)
|
||||
.group(),
|
||||
)
|
||||
.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))| {
|
||||
let head = if i == 0 { "if " } else { "else if " };
|
||||
(f.reflow(head)
|
||||
.append(expr(c, f, &cond.value))
|
||||
.append(expr(c, Free, f, &cond.value))
|
||||
.group()
|
||||
.nest(2))
|
||||
.append(f.line())
|
||||
.append(
|
||||
f.reflow("then")
|
||||
.append(f.softline().append(expr(c, f, &body.value)))
|
||||
.append(f.softline().append(expr(c, Free, f, &body.value)))
|
||||
.group()
|
||||
.nest(2),
|
||||
)
|
||||
|
@ -77,7 +108,7 @@ fn expr<'a>(c: &Ctx, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a, Arena<'a>>
|
|||
}))
|
||||
.append(
|
||||
f.reflow("else ")
|
||||
.append(expr(c, f, &final_else.value))
|
||||
.append(expr(c, Free, f, &final_else.value))
|
||||
.group()
|
||||
.nest(2),
|
||||
)
|
||||
|
@ -86,12 +117,17 @@ fn expr<'a>(c: &Ctx, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a, Arena<'a>>
|
|||
LetNonRec(_, _) => todo!(),
|
||||
Call(fun, args, _) => {
|
||||
let (_, fun, _, _) = &**fun;
|
||||
f.text("(")
|
||||
.append(expr(c, f, &fun.value))
|
||||
.append(f.softline())
|
||||
.append(f.intersperse(args.iter().map(|le| expr(c, f, &le.1.value)), f.softline()))
|
||||
.append(f.text(")"))
|
||||
.group()
|
||||
maybe_paren!(
|
||||
Free,
|
||||
p,
|
||||
expr(c, CallArg, f, &fun.value)
|
||||
.append(f.softline())
|
||||
.append(f.intersperse(
|
||||
args.iter().map(|le| expr(c, CallArg, f, &le.1.value)),
|
||||
f.softline()
|
||||
))
|
||||
.group()
|
||||
)
|
||||
}
|
||||
RunLowLevel { .. } => 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(
|
||||
arguments
|
||||
.iter()
|
||||
.map(|(_, _, arg)| pattern(c, f, &arg.value)),
|
||||
.map(|(_, _, arg)| pattern(c, PPrec::Free, f, &arg.value)),
|
||||
f.text(", "),
|
||||
),
|
||||
)
|
||||
.append(f.text(" ->"))
|
||||
.append(f.line())
|
||||
.append(expr(c, f, &loc_body.value))
|
||||
.append(expr(c, Free, f, &loc_body.value))
|
||||
.nest(2)
|
||||
.group(),
|
||||
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
|
||||
.text(name.as_str())
|
||||
.append(f.reflow(": "))
|
||||
.append(expr(c, f, &field.loc_expr.value))
|
||||
.append(expr(c, Free, f, &field.loc_expr.value))
|
||||
.nest(2)
|
||||
.group();
|
||||
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("{}"),
|
||||
Access {
|
||||
loc_expr, field, ..
|
||||
} => f
|
||||
.text("(")
|
||||
.append(expr(c, f, &loc_expr.value))
|
||||
.append(f.text(")"))
|
||||
} => expr(c, CallArg, f, &loc_expr.value)
|
||||
.append(f.text(format!(".{}", field.as_str())))
|
||||
.group(),
|
||||
Accessor(_) => todo!(),
|
||||
|
@ -161,21 +194,35 @@ fn branch<'a>(c: &Ctx, f: &'a Arena<'a>, b: &'a WhenBranch) -> DocBuilder<'a, Ar
|
|||
} = b;
|
||||
|
||||
f.intersperse(
|
||||
patterns.iter().map(|lp| pattern(c, f, &lp.value)),
|
||||
patterns
|
||||
.iter()
|
||||
.map(|lp| pattern(c, PPrec::Free, f, &lp.value)),
|
||||
f.text(" | "),
|
||||
)
|
||||
.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(),
|
||||
})
|
||||
.append(f.text(" ->"))
|
||||
.append(f.softline())
|
||||
.append(expr(c, f, &value.value))
|
||||
.append(f.line())
|
||||
.append(expr(c, EPrec::Free, f, &value.value))
|
||||
.nest(2)
|
||||
.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::*;
|
||||
match p {
|
||||
Identifier(sym)
|
||||
|
@ -190,19 +237,30 @@ fn pattern<'a>(c: &Ctx, f: &'a Arena<'a>, p: &'a Pattern) -> DocBuilder<'a, Aren
|
|||
tag_name,
|
||||
arguments,
|
||||
..
|
||||
} => f
|
||||
.text(format!("({}", tag_name.0.as_str()))
|
||||
.append(f.intersperse(
|
||||
arguments.iter().map(|(_, lp)| pattern(c, f, &lp.value)),
|
||||
f.space(),
|
||||
))
|
||||
.append(")")
|
||||
.group(),
|
||||
} => maybe_paren!(
|
||||
Free,
|
||||
prec,
|
||||
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(),
|
||||
)
|
||||
)
|
||||
.group()
|
||||
),
|
||||
UnwrappedOpaque {
|
||||
opaque, argument, ..
|
||||
} => f
|
||||
.text(format!("@{} ", opaque.module_string(c.interns)))
|
||||
.append(pattern(c, f, &argument.1.value))
|
||||
.append(pattern(c, Free, f, &argument.1.value))
|
||||
.group(),
|
||||
RecordDestructure { destructs, .. } => f
|
||||
.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
|
||||
.text(label.as_str())
|
||||
.append(f.text(" ? "))
|
||||
.append(expr(c, f, &e.value)),
|
||||
.append(expr(c, EPrec::Free, f, &e.value)),
|
||||
roc_can::pattern::DestructType::Guard(_, p) => f
|
||||
.text(label.as_str())
|
||||
.append(f.text(": "))
|
||||
.append(pattern(c, f, &p.value)),
|
||||
.append(pattern(c, Free, f, &p.value)),
|
||||
},
|
||||
),
|
||||
f.text(", "),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue