Skip to content

Commit cbc8688

Browse files
committedOct 22, 2022
Pretty-print debug outputs
1 parent d06585f commit cbc8688

File tree

4 files changed

+143
-32
lines changed

4 files changed

+143
-32
lines changed
 

‎shared/src/main/scala/mlscript/Typer.scala

+3-12
Original file line numberDiff line numberDiff line change
@@ -723,21 +723,12 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool)
723723
case iff @ If(body, fallback) =>
724724
try {
725725
val cnf = desugarIf(body)(ctx)
726-
println("Flattened conjunctions")
727-
cnf.foreach { case (conditions, term) =>
728-
println(conditions.iterator.map {
729-
case IfBodyHelpers.Condition.BooleanTest(test) => s"<$test>"
730-
case IfBodyHelpers.Condition.MatchClass(scrutinee, Var(className), fields) =>
731-
s"$scrutinee is $className"
732-
case IfBodyHelpers.Condition.MatchTuple(scrutinee, arity, fields) =>
733-
s"$scrutinee is Tuple#$arity"
734-
}.mkString("", " and ", s" => $term"))
735-
}
726+
IfBodyHelpers.showConjunctions(println, cnf)
736727
val caseTree = MutCaseOf.build(cnf)
737728
println("The mutable CaseOf tree")
738-
println(caseTree.toString)
729+
MutCaseOf.show(caseTree).foreach(println(_))
739730
val trm = caseTree.toTerm(fallback)
740-
println(s"Desugared term: $trm")
731+
println(s"Desugared term: ${trm.print(false)}")
741732
iff.desugaredIf = S(trm)
742733
typeTerm(trm)
743734
} catch {

‎shared/src/main/scala/mlscript/helpers.scala

+60-2
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,8 @@ trait TermImpl extends StatementImpl { self: Term =>
401401
case Bind(l, r) => s"$l as $r" |> bra
402402
case Test(l, r) => s"$l is $r" |> bra
403403
case With(t, fs) => s"$t with $fs" |> bra
404-
case CaseOf(s, c) => s"case $s of $c" |> bra
404+
case CaseOf(s, c) =>
405+
s"case $s of { ${c.print(true)} }" |> bra
405406
case Subs(a, i) => s"($a)[$i]"
406407
case Assign(lhs, rhs) => s" $lhs <- $rhs" |> bra
407408
case New(S((at, ar)), bod) => s"new ${at.show}($ar) ${bod.show}" |> bra
@@ -727,7 +728,16 @@ trait CaseBranchesImpl extends Located { self: CaseBranches =>
727728
case c: Case => c :: c.rest.toList
728729
case _ => Nil
729730
}
730-
731+
732+
def print(isFirst: Bool): Str = this match {
733+
case Case(pat, body, rest) =>
734+
(if (isFirst) { "" } else { "; " }) +
735+
pat.print(false) + " => " + body.print(false) + rest.print(false)
736+
case Wildcard(body) =>
737+
(if (isFirst) { "" } else { "; " }) +
738+
"_ => " + body.print(false)
739+
case NoCases => ""
740+
}
731741
}
732742

733743
abstract class MatchCase
@@ -846,6 +856,19 @@ object IfBodyHelpers {
846856
case (field -> alias) :: tail =>
847857
Let(false, alias, Sel(scrutinee, Var(field)), mkLetFromFields(scrutinee, tail, body))
848858
}
859+
860+
def showConjunctions(println: (=> Any) => Unit, cnf: Ls[Ls[IfBodyHelpers.Condition] -> Term]): Unit = {
861+
println("Flattened conjunctions")
862+
cnf.foreach { case (conditions, term) =>
863+
println("+ " + conditions.iterator.map {
864+
case IfBodyHelpers.Condition.BooleanTest(test) => s"<$test>"
865+
case IfBodyHelpers.Condition.MatchClass(scrutinee, Var(className), fields) =>
866+
s"$scrutinee is $className"
867+
case IfBodyHelpers.Condition.MatchTuple(scrutinee, arity, fields) =>
868+
s"$scrutinee is Tuple#$arity"
869+
}.mkString("", " and ", s" => $term"))
870+
}
871+
}
849872
}
850873

851874
abstract class MutCaseOf {
@@ -856,6 +879,41 @@ abstract class MutCaseOf {
856879
object MutCaseOf {
857880
import IfBodyHelpers._
858881

882+
def show(t: MutCaseOf): Ls[Str] = {
883+
val lines = Buffer.empty[String]
884+
def rec(t: MutCaseOf, indent: Int, leading: String): Unit = {
885+
val baseIndent = " " * indent
886+
t match {
887+
case IfThenElse(condition, whenTrue, whenFalse) =>
888+
// Output the `whenTrue` with the prefix "if".
889+
lines += baseIndent + leading + s"if «$condition"
890+
rec(whenTrue, indent + 1, "")
891+
// Output the `whenFalse` case with the prefix "else".
892+
lines += s"$baseIndent${leading}else"
893+
rec(whenFalse, indent + 1, "")
894+
case Match(scrutinee, branches) =>
895+
lines += baseIndent + leading + s"«$scrutinee» match"
896+
branches.foreach {
897+
case Branch(N, consequent) =>
898+
lines += s"$baseIndent default"
899+
rec(consequent, indent + 2, "")
900+
case Branch(S(Var(className) -> fields), consequent) =>
901+
lines += s"$baseIndent case $className =>"
902+
fields.foreach { case (field, Var(alias)) =>
903+
lines += s"$baseIndent let $alias = .$field"
904+
}
905+
rec(consequent, indent + 2, "")
906+
}
907+
case Consequent(term) =>
908+
lines += s"$baseIndent$leading«$term»"
909+
case MissingCase =>
910+
lines += s"$baseIndent$leading<missing case>"
911+
}
912+
}
913+
rec(t, 0, "")
914+
lines.toList
915+
}
916+
859917
final case class Branch(
860918
val patternFields: Opt[Var -> Buffer[Str -> Var]],
861919
var consequent: MutCaseOf

‎shared/src/test/diff/nu/Humiliation.mls

+18-18
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ if f is
2424
Foo(a) then a
2525
//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing
2626
//│ at: scala.Predef$.$qmark$qmark$qmark(Predef.scala:344)
27-
//│ at: mlscript.MutCaseOf$Consequent.append(helpers.scala:955)
28-
//│ at: mlscript.MutCaseOf$Match.append(helpers.scala:918)
29-
//│ at: mlscript.MutCaseOf$.$anonfun$build$1(helpers.scala:990)
30-
//│ at: mlscript.MutCaseOf$.$anonfun$build$1$adapted(helpers.scala:990)
27+
//│ at: mlscript.MutCaseOf$Consequent.append(helpers.scala:1013)
28+
//│ at: mlscript.MutCaseOf$Match.append(helpers.scala:976)
29+
//│ at: mlscript.MutCaseOf$.$anonfun$build$1(helpers.scala:1048)
30+
//│ at: mlscript.MutCaseOf$.$anonfun$build$1$adapted(helpers.scala:1048)
3131
//│ at: scala.collection.immutable.List.foreach(List.scala:333)
32-
//│ at: mlscript.MutCaseOf$.build(helpers.scala:990)
33-
//│ at: mlscript.Typer.$anonfun$typeTerm$2(Typer.scala:736)
32+
//│ at: mlscript.MutCaseOf$.build(helpers.scala:1048)
33+
//│ at: mlscript.Typer.$anonfun$typeTerm$2(Typer.scala:727)
3434
//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:30)
35-
//│ at: mlscript.Typer.typeTerm(Typer.scala:753)
35+
//│ at: mlscript.Typer.typeTerm(Typer.scala:744)
3636

3737

3838
class Bar(y, z)
@@ -58,15 +58,15 @@ if x is
5858
Pair(y, 1) then x
5959
//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing
6060
//│ at: scala.Predef$.$qmark$qmark$qmark(Predef.scala:344)
61-
//│ at: mlscript.MutCaseOf$IfThenElse.append(helpers.scala:890)
62-
//│ at: mlscript.MutCaseOf$Match.append(helpers.scala:918)
63-
//│ at: mlscript.MutCaseOf$.$anonfun$build$1(helpers.scala:990)
64-
//│ at: mlscript.MutCaseOf$.$anonfun$build$1$adapted(helpers.scala:990)
61+
//│ at: mlscript.MutCaseOf$IfThenElse.append(helpers.scala:948)
62+
//│ at: mlscript.MutCaseOf$Match.append(helpers.scala:976)
63+
//│ at: mlscript.MutCaseOf$.$anonfun$build$1(helpers.scala:1048)
64+
//│ at: mlscript.MutCaseOf$.$anonfun$build$1$adapted(helpers.scala:1048)
6565
//│ at: scala.collection.immutable.List.foreach(List.scala:333)
66-
//│ at: mlscript.MutCaseOf$.build(helpers.scala:990)
67-
//│ at: mlscript.Typer.$anonfun$typeTerm$2(Typer.scala:736)
66+
//│ at: mlscript.MutCaseOf$.build(helpers.scala:1048)
67+
//│ at: mlscript.Typer.$anonfun$typeTerm$2(Typer.scala:727)
6868
//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:30)
69-
//│ at: mlscript.Typer.typeTerm(Typer.scala:753)
69+
//│ at: mlscript.Typer.typeTerm(Typer.scala:744)
7070

7171
class Z()
7272
class O()
@@ -147,13 +147,13 @@ fun foo(x, y) = if x is Z() and y is O() then 0 else 1
147147
//│ at: scala.Predef$.$qmark$qmark$qmark(Predef.scala:344)
148148
//│ at: mlscript.Typer.$anonfun$typeTerm$2(Typer.scala:626)
149149
//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:30)
150-
//│ at: mlscript.Typer.typeTerm(Typer.scala:753)
150+
//│ at: mlscript.Typer.typeTerm(Typer.scala:744)
151151
//│ at: mlscript.Typer.$anonfun$typeTerm$2(Typer.scala:714)
152152
//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:30)
153-
//│ at: mlscript.Typer.typeTerm(Typer.scala:753)
154-
//│ at: mlscript.Typer.$anonfun$typeTerm$2(Typer.scala:742)
153+
//│ at: mlscript.Typer.typeTerm(Typer.scala:744)
154+
//│ at: mlscript.Typer.$anonfun$typeTerm$2(Typer.scala:733)
155155
//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:30)
156-
//│ at: mlscript.Typer.typeTerm(Typer.scala:753)
156+
//│ at: mlscript.Typer.typeTerm(Typer.scala:744)
157157

158158
fun foo(x, y) = if x is
159159
Z() and y is O() then 0 else 1

‎shared/src/test/diff/nu/TrivialIf.mls

+62
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,72 @@ class None: Option
1414
//│ Some: 'value -> (Some with {value: 'value})
1515
//│ None: () -> None
1616

17+
:d
1718
fun getOrElse(opt, default) =
1819
if opt is
1920
Some(value) then value
2021
None then default
22+
//│ 1. Typing term opt, default, => {if opt is ‹(Some (value,)) then value; (None) then default›}
23+
//│ | 1. Typing pattern opt, default,
24+
//│ | | 1. Typing pattern opt
25+
//│ | | 1. : α48'
26+
//│ | | 1. Typing pattern default
27+
//│ | | 1. : α49'
28+
//│ | 1. : (α48', α49',)
29+
//│ | 1. Typing term {if opt is ‹(Some (value,)) then value; (None) then default›}
30+
//│ | | 1. Typing term if opt is ‹(Some (value,)) then value; (None) then default›
31+
//│ | | | Flattened conjunctions
32+
//│ | | | + opt is Some => value
33+
//│ | | | + opt is None => default
34+
//│ | | | The mutable CaseOf tree
35+
//│ | | | «opt» match
36+
//│ | | | case Some =>
37+
//│ | | | let value = .value
38+
//│ | | | «value»
39+
//│ | | | case None =>
40+
//│ | | | «default»
41+
//│ | | | Desugared term: case opt of { Some => let value = (opt).value in value; None => default }
42+
//│ | | | 1. Typing term case opt of { Some => let value = (opt).value in value; None => default }
43+
//│ | | | | 1. Typing term opt
44+
//│ | | | | 1. : α48'
45+
//│ | | | | 1. Typing term let value = (opt).value in value
46+
//│ | | | | | 2. Typing term (opt).value
47+
//│ | | | | | | 2. Typing term opt
48+
//│ | | | | | | 2. : α50'
49+
//│ | | | | | | CONSTRAIN α50' <! {value: value51''}
50+
//│ | | | | | | where
51+
//│ | | | | | | C α50' <! {value: value51''} (0)
52+
//│ | | | | | | | EXTR RHS {value: value51''} ~> {value: value52'} to 1
53+
//│ | | | | | | | where
54+
//│ | | | | | | | and
55+
//│ value51'' :> value52'
56+
//│ | | | | | | | C α50' <! {value: value52'} (1)
57+
//│ | | | | | 2. : value51''
58+
//│ | | | | | 1. Typing term value
59+
//│ | | | | | 1. : value53'
60+
//│ | | | | 1. : value53'
61+
//│ | | | | 1. Typing term default
62+
//│ | | | | 1. : α49'
63+
//│ | | | | CONSTRAIN α48' <! ((some<option> & α50') | ((none<option> & α54') & ~(some<option>)))
64+
//│ | | | | where
65+
//│ α50' <: {value: value52'}
66+
//│ | | | | C α48' <! ((some<option> & α50') | ((none<option> & α54') & ~(some<option>))) (0)
67+
//│ | | | 1. : (value53' | α49')
68+
//│ | | 1. : (value53' | α49')
69+
//│ | 1. : (value53' | α49')
70+
//│ 1. : ((α48', α49',) -> (value53' | α49'))
71+
//│ CONSTRAIN ((α48', α49',) -> (value53' | α49')) <! getOrElse47'
72+
//│ where
73+
//│ α48' <: ((some<option> & α50') | ((none<option> & α54') & ~(some<option>)))
74+
//│ α50' <: {value: value52'}
75+
//│ value53' :> value52'
76+
//│ C ((α48', α49',) -> (value53' | α49')) <! getOrElse47' (0)
77+
//│ ⬤ Typed as: getOrElse47'
78+
//│ where:
79+
//│ getOrElse47' :> ((α48', α49',) -> (value53' | α49'))
80+
//│ α48' <: ((some<option> & α50') | ((none<option> & α54') & ~(some<option>)))
81+
//│ α50' <: {value: value52'}
82+
//│ value53' :> value52'
2183
//│ getOrElse: (None | (Some with {value: 'value}), 'value,) -> 'value
2284

2385
getOrElse(None(), 0)

0 commit comments

Comments
 (0)