Skip to content

Instantly share code, notes, and snippets.

@cb372
Created October 7, 2016 11:27
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cb372/262a9e935dba5de740a8e26909237419 to your computer and use it in GitHub Desktop.
Save cb372/262a9e935dba5de740a8e26909237419 to your computer and use it in GitHub Desktop.
Prettier AST trees for debugging macros
import scala.reflect.macros.blackbox
object PrettyPrinting {
/*
* Print a raw AST, nicely indented.
* Pretty fragile, e.g. will get confused by string literals containing commas or parentheses.
*/
def prettyTree(raw: String): String = {
var level = 0
def indent = " " * level
val sparse = raw.map {
case ',' => s",\n$indent".dropRight(1)
case '(' =>
level += 1
s"(\n$indent"
case ')' =>
level -= 1
s"\n$indent)"
case other => other
}.mkString
sparse.replaceAll("""\(\s+\)""", "()")
}
def prettyTree(c: blackbox.Context)(tree: c.universe.Tree): String =
prettyTree(c.universe.showRaw(tree))
}
Block(List(ClassDef(Modifiers(ABSTRACT | INTERFACE | SEALED | DEFAULTPARAM/TRAIT), TypeName("Foo"), List(), Template(List(Select(Ident(scala), TypeName("AnyRef"))), noSelfType, List())), ModuleDef(Modifiers(), TermName("Foo"), Template(List(Select(Ident(scala), TypeName("AnyRef"))), noSelfType, List(DefDef(Modifiers(), termNames.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(())))), ValDef(Modifiers(), TermName("a"), TypeTree(), TypeApply(Select(Select(Select(Ident(TermName("monocle")), TermName("macros")), TermName("GenPrism")), TermName("apply")), List(Ident(TypeName("Foo")), Ident(TypeName("A"))))), ValDef(Modifiers(), TermName("b"), TypeTree(), TypeApply(Select(Select(Select(Ident(TermName("monocle")), TermName("macros")), TermName("GenPrism")), TermName("apply")), List(Ident(TypeName("Foo")), Ident(TypeName("B"))))))))), Literal(Constant(())))
Block(
List(
ClassDef(
Modifiers(
ABSTRACT | INTERFACE | SEALED | DEFAULTPARAM/TRAIT
),
TypeName(
"Foo"
),
List(),
Template(
List(
Select(
Ident(
scala
),
TypeName(
"AnyRef"
)
)
),
noSelfType,
List()
)
),
ModuleDef(
Modifiers(),
TermName(
"Foo"
),
Template(
List(
Select(
Ident(
scala
),
TypeName(
"AnyRef"
)
)
),
noSelfType,
List(
DefDef(
Modifiers(),
termNames.CONSTRUCTOR,
List(),
List(
List()
),
TypeTree(),
Block(
List(
pendingSuperCall
),
Literal(
Constant(
()
)
)
)
),
ValDef(
Modifiers(),
TermName(
"a"
),
TypeTree(),
TypeApply(
Select(
Select(
Select(
Ident(
TermName(
"monocle"
)
),
TermName(
"macros"
)
),
TermName(
"GenPrism"
)
),
TermName(
"apply"
)
),
List(
Ident(
TypeName(
"Foo"
)
),
Ident(
TypeName(
"A"
)
)
)
)
),
ValDef(
Modifiers(),
TermName(
"b"
),
TypeTree(),
TypeApply(
Select(
Select(
Select(
Ident(
TermName(
"monocle"
)
),
TermName(
"macros"
)
),
TermName(
"GenPrism"
)
),
TermName(
"apply"
)
),
List(
Ident(
TypeName(
"Foo"
)
),
Ident(
TypeName(
"B"
)
)
)
)
)
)
)
)
),
Literal(
Constant(
()
)
)
)
@olafurpg
Copy link

olafurpg commented Oct 7, 2016

I raise you with an even more hacky implementation that gives slightly more compact output!

> def clangPrint(x: Any): String = {
    import scala.sys.process._
    import java.io.ByteArrayInputStream
    val bais = new ByteArrayInputStream(x.toString.getBytes("UTF-8"))
    val command = List("clang-format",
                       "-style={ContinuationIndentWidth: 2, ColumnLimit: 120}")
    (command #< bais).!!.trim
  }
> show(clangPrint("""Block(List(ClassDef(Modifiers(ABSTRACT | INTERFACE | SEALED | DEFAULTPARAM/TRAIT), TypeName("Foo"), List(), Template(List(Select(Ident(scala), TypeName("AnyRef"))), noSelfType, List())), ModuleDef(Modifiers(), TermName("Foo"), Template(List(Select(Ident(scala), TypeName("AnyRef"))), noSelfType, List(DefDef(Modifiers(), termNames.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(())))), ValDef(Modifiers(), TermName("a"), TypeTree(), TypeApply(Select(Select(Select(Ident(TermName("monocle")), TermName("macros")), TermName("GenPrism")), TermName("apply")), List(Ident(TypeName("Foo")), Ident(TypeName("A"))))), ValDef(Modifiers(), TermName("b"), TypeTree(), TypeApply(Select(Select(Select(Ident(TermName("monocle")), TermName("macros")), TermName("GenPrism")), TermName("apply")), List(Ident(TypeName("Foo")), Ident(TypeName("B"))))))))), Literal(Constant(())))
Raw
"""))
"""
Block(
  List(ClassDef(Modifiers(ABSTRACT | INTERFACE | SEALED | DEFAULTPARAM / TRAIT), TypeName("Foo"), List(),
                Template(List(Select(Ident(scala), TypeName("AnyRef"))), noSelfType, List())),
       ModuleDef(Modifiers(), TermName("Foo"),
                 Template(List(Select(Ident(scala), TypeName("AnyRef"))), noSelfType,
                          List(DefDef(Modifiers(), termNames.CONSTRUCTOR, List(), List(List()), TypeTree(),
                                      Block(List(pendingSuperCall), Literal(Constant(())))),
                               ValDef(Modifiers(), TermName("a"), TypeTree(),
                                      TypeApply(Select(Select(Select(Ident(TermName("monocle")), TermName("macros")),
                                                              TermName("GenPrism")),
                                                       TermName("apply")),
                                                List(Ident(TypeName("Foo")), Ident(TypeName("A"))))),
                               ValDef(Modifiers(), TermName("b"), TypeTree(),
                                      TypeApply(Select(Select(Select(Ident(TermName("monocle")), TermName("macros")),
                                                              TermName("GenPrism")),
                                                       TermName("apply")),
                                                List(Ident(TypeName("Foo")), Ident(TypeName("B"))))))))),
  Literal(Constant(()))) Raw
"""

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment