summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimirNik <vladimir.nikolaev9@gmail.com>2014-01-05 22:11:02 +0400
committerVladimirNik <vladimir.nikolaev9@gmail.com>2014-01-05 22:11:02 +0400
commit0ac5c568378aa521089e01d473745840c64a2333 (patch)
treef796ef9a1f29ae154f59cb1082ec6e47f0c5a366
parent6536256f0e2a736aa0c6bb9410883bf9fec4386e (diff)
downloadscala-0ac5c568378aa521089e01d473745840c64a2333.tar.gz
scala-0ac5c568378aa521089e01d473745840c64a2333.tar.bz2
scala-0ac5c568378aa521089e01d473745840c64a2333.zip
toCode is added to Printers
1. Printers API is updated (def toCode) 2. ParsedTreePrinter is added to internal.Printers. ParsedTreePrinter generates the code for passed unattributed trees. Generated code can be later compiled by scalac retaining the same meaning.
-rw-r--r--src/reflect/scala/reflect/api/Printers.scala19
-rw-r--r--src/reflect/scala/reflect/internal/Printers.scala615
2 files changed, 634 insertions, 0 deletions
diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala
index 6e2e2c3781..f4ce1fcc64 100644
--- a/src/reflect/scala/reflect/api/Printers.scala
+++ b/src/reflect/scala/reflect/api/Printers.scala
@@ -201,6 +201,25 @@ trait Printers { self: Universe =>
*/
protected def newTreePrinter(out: PrintWriter): TreePrinter
+ /**
+ * Renders the code of the passed tree, so that:
+ * 1) it can be later compiled by scalac retaining the same meaning,
+ * 2) it looks pretty.
+ * At the moment we have handled #1 for unattributed trees and
+ * later on plan to account for typical idiosyncrasies of the typechecker.
+ * #2 is more or less okay indentation-wise, but at the moment there's a lot of desugaring
+ * left in place, and that's what we also plan to improve in the future.
+ *
+ * @group Printers
+ */
+ def toCode(tree: Tree) = render(tree, newCodePrinter)
+
+ /**
+ * Hook to define what `toCode(...)` means.
+ * @group Printers
+ */
+ protected def newCodePrinter(out: PrintWriter): TreePrinter
+
/** Renders internal structure of a reflection artifact as the
* visualization of a Scala syntax tree.
*
diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala
index 120cc04b22..f93a68b11c 100644
--- a/src/reflect/scala/reflect/internal/Printers.scala
+++ b/src/reflect/scala/reflect/internal/Printers.scala
@@ -458,11 +458,626 @@ trait Printers extends api.Printers { self: SymbolTable =>
out.print(if (arg == null) "null" else arg.toString)
}
}
+
+ //printer for trees after parser and before typer phases
+ class ParsedTreePrinter(out: PrintWriter) extends TreePrinter(out) {
+ override def withTypes = this
+ override def withIds = this
+ override def withKinds = this
+ override def withMirrors = this
+ override def withPositions = this
+
+ //add print parameters to typed trees printer
+ printTypes = false
+ printIds = false
+ printKinds = false
+ printMirrors = false
+ printPositions = false
+
+ protected val parentsStack = scala.collection.mutable.Stack[Tree]()
+
+ protected def currentTree = if (parentsStack.nonEmpty) Some(parentsStack.top) else None
+
+ protected def currentParent = if (parentsStack.length > 1) Some(parentsStack(1)) else None
+
+ protected def printedName(name: Name, decoded: Boolean = true) = {
+ import Chars._
+ val decName = name.decoded
+ val bslash = '\\'
+ val brackets = List('[',']','(',')','{','}')
+
+ def addBackquotes(s: String) =
+ if (decoded && (decName.exists(ch => brackets.contains(ch) || isWhitespace(ch)) ||
+ (name.isOperatorName && decName.exists(isOperatorPart) && decName.exists(isScalaLetter) && !decName.contains(bslash))))
+ s"`$s`" else s
+
+ if (name == nme.CONSTRUCTOR) "this"
+ else addBackquotes(quotedName(name, decoded))
+ }
+
+ protected def isIntLitWithDecodedOp(qual: Tree, name: Name) = {
+ val qualIsIntLit = qual match {
+ case Literal(Constant(x: Int)) => true
+ case _ => false
+ }
+ qualIsIntLit && name.isOperatorName
+ }
+
+ protected def needsParentheses(parent: Tree)(insideIf: Boolean = true, insideMatch: Boolean = true,
+ insideTry: Boolean = true, insideAnnotated: Boolean = true, insideBlock: Boolean = true, insideLabelDef: Boolean = true) = {
+ parent match {
+ case _: If => insideIf
+ case _: Match => insideMatch
+ case _: Try => insideTry
+ case _: Annotated => insideAnnotated
+ case _: Block => insideBlock
+ case _: LabelDef => insideLabelDef
+ case _ => false
+ }
+ }
+
+ protected def parenthesize(condition: Boolean = true)(body: => Unit) {
+ if (condition) print("(")
+ body
+ if (condition) print(")")
+ }
+
+ protected def printImplicitInParamsList(vds: List[ValDef]) =
+ if (vds.nonEmpty) printFlags(vds.head.mods.flags & IMPLICIT, "")
+
+ def printValueParams(ts: List[ValDef], inParentheses: Boolean) {
+ parenthesize(inParentheses){
+ printImplicitInParamsList(ts)
+ printSeq(ts){printParam}{print(", ")}
+ }
+ }
+
+ protected def checkForBlank(cond: Boolean) = if (cond) " " else ""
+ protected def blankForOperatorName(name: Name) = checkForBlank(name.isOperatorName)
+ protected def blankForName(name: Name) = checkForBlank(name.isOperatorName || name.endsWith("_"))
+
+ protected def resolveSelect(t: Tree): String = {
+ t match {
+ //case for: 1) (if (a) b else c).meth1.meth2 or 2) 1 + 5 should be represented as (1).+(5)
+ case Select(qual, name) if (name.isTermName && needsParentheses(qual)(insideLabelDef = false)) || isIntLitWithDecodedOp(qual, name) => s"(${resolveSelect(qual)}).${printedName(name)}"
+ case Select(qual, name) if name.isTermName => s"${resolveSelect(qual)}.${printedName(name)}"
+ case Select(qual, name) if name.isTypeName => s"${resolveSelect(qual)}#${blankForOperatorName(name)}%${printedName(name)}"
+ case Ident(name) => printedName(name)
+ case _ => toCode(t)
+ }
+ }
+
+ val defaultClasses = List(tpnme.AnyRef)
+ val defaultTraitsForCase = List(tpnme.Product, tpnme.Serializable)
+ protected def removeDefaultTypesFromList(trees: List[Tree])(classesToRemove: List[Name] = defaultClasses)(traitsToRemove: List[Name]) = {
+ def removeDefaultTraitsFromList(trees: List[Tree], traitsToRemove: List[Name]): List[Tree] =
+ trees match {
+ case Nil => trees
+ case init :+ last => last match {
+ case Select(Ident(sc), name) if traitsToRemove.contains(name) && sc == nme.scala_ =>
+ removeDefaultTraitsFromList(init, traitsToRemove)
+ case _ => trees
+ }
+ }
+
+ removeDefaultTraitsFromList(removeDefaultClassesFromList(trees, classesToRemove), traitsToRemove)
+ }
+
+ protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) = trees filter {
+ case Select(Ident(sc), name) => !(classesToRemove.contains(name) && sc == nme.scala_)
+ case _ => true
+ }
+
+ def printFlags(mods: Modifiers, primaryCtorParam: Boolean = false) {
+ val base = AccessFlags | OVERRIDE | ABSTRACT | FINAL | SEALED | LAZY
+ val mask = if (primaryCtorParam) base else base | IMPLICIT
+
+ val s = mods.flagString(mask)
+ if (s != "") print(s"$s ")
+ //case flag should be the last
+ if (mods.isCase) print(mods.flagBitsToString(CASE) + " ")
+ if (mods.isAbstractOverride) print("abstract override ")
+ }
+
+ override def printModifiers(tree: Tree, mods: Modifiers): Unit = printModifiers(mods, primaryCtorParam = false)
+
+ def printModifiers(mods: Modifiers, primaryCtorParam: Boolean): Unit = {
+ def modsAccepted = List(currentTree, currentParent) exists (_ map {
+ case _: ClassDef | _: ModuleDef | _: Template | _: PackageDef => true
+ case _ => false
+ } getOrElse false)
+
+ if (currentParent.isEmpty || modsAccepted)
+ printFlags(mods, primaryCtorParam)
+ else
+ List(IMPLICIT, CASE, LAZY, SEALED).foreach{flag => if (mods.hasFlag(flag)) print(s"${mods.flagBitsToString(flag)} ")}
+ }
+
+ def printParam(tree: Tree, primaryCtorParam: Boolean) {
+ tree match {
+ case vd @ ValDef(mods, name, tp, rhs) =>
+ printAnnotations(vd)
+ val mutableOrOverride = mods.isOverride || mods.isMutable
+ val hideCtorMods = mods.isParamAccessor && mods.isPrivateLocal && !mutableOrOverride
+ val hideCaseCtorMods = mods.isCaseAccessor && mods.isPublic && !mutableOrOverride
+
+ if (primaryCtorParam && !(hideCtorMods || hideCaseCtorMods)) {
+ printModifiers(mods, primaryCtorParam)
+ print(if (mods.isMutable) "var " else "val ");
+ }
+ print(printedName(name), blankForName(name));
+ printOpt(": ", tp);
+ printOpt(" = ", rhs)
+ case TypeDef(_, name, tparams, rhs) =>
+ print(printedName(name))
+ printTypeParams(tparams);
+ print(rhs)
+ case _ =>
+ super.printParam(tree)
+ }
+ }
+
+ override def printParam(tree: Tree) {
+ printParam(tree, primaryCtorParam = false)
+ }
+
+ protected def printArgss(argss: List[List[Tree]]) =
+ argss foreach {x: List[Tree] => if (!(x.isEmpty && argss.size == 1)) printRow(x, "(", ", ", ")")}
+
+ override def printAnnotations(tree: Tree) {
+ tree match {
+ case md: MemberDef =>
+ val annots = md.mods.annotations
+ annots foreach {
+ case treeInfo.Applied(core, _, argss) =>
+ print("@")
+ core match {
+ case Select(New(tree), _) => print(tree)
+ case _ =>
+ }
+ printArgss(argss)
+ print(" ")
+ case _ => super.printTree(md)
+ }
+ case _ => super.printTree(tree)
+ }
+ }
+
+ protected def printPackageDef(tree: PackageDef, separator: String) {
+ val PackageDef(packaged, stats) = tree
+ printAnnotations(tree)
+ print("package ", packaged); printColumn(stats, " {", separator, "}")
+ }
+
+ protected def printValDef(tree: ValDef, resultName: => String)(printTypeSignature: => Unit)(printRhs: => Unit) {
+ val ValDef(mods, name, tp, rhs) = tree
+ printAnnotations(tree)
+ printModifiers(tree, mods)
+ print(if (mods.isMutable) "var " else "val ", resultName)
+ printTypeSignature
+ printRhs
+ }
+
+ protected def printDefDef(tree: DefDef, resultName: => String)(printTypeSignature: => Unit)(printRhs: => Unit) {
+ val DefDef(mods, name, tparams, vparamss, tp, rhs) = tree
+ printAnnotations(tree)
+ printModifiers(tree, mods)
+ print("def " + resultName)
+ printTypeParams(tparams);
+ vparamss foreach printValueParams
+ printTypeSignature
+ printRhs
+ }
+
+ protected def printTypeDef(tree: TypeDef, resultName: => String) {
+ val TypeDef(mods, name, tparams, rhs) = tree
+ if (mods hasFlag (PARAM | DEFERRED)) {
+ printAnnotations(tree)
+ printModifiers(tree, mods)
+ print("type ")
+ printParam(tree)
+ } else {
+ printAnnotations(tree)
+ printModifiers(tree, mods)
+ print("type " + resultName)
+ printTypeParams(tparams)
+ printOpt(" = ", rhs)
+ }
+ }
+
+ protected def printImport(tree: Import, resSelect: => String) {
+ val Import(expr, selectors) = tree
+ // Is this selector renaming a name (i.e, {name1 => name2})
+ def isNotRename(s: ImportSelector): Boolean =
+ s.name == nme.WILDCARD || s.name == s.rename
+
+ def selectorToString(s: ImportSelector): String = {
+ val from = quotedName(s.name)
+ if (isNotRename(s)) from
+ else from + "=>" + quotedName(s.rename)
+ }
+ print("import ", resSelect, ".")
+ selectors match {
+ case List(s) =>
+ // If there is just one selector and it is not renaming a name, no braces are needed
+ if (isNotRename(s)) print(selectorToString(s))
+ else print("{", selectorToString(s), "}")
+ // If there is more than one selector braces are always needed
+ case many =>
+ print(many.map(selectorToString).mkString("{", ", ", "}"))
+ }
+ }
+
+ protected def printCaseDef(tree: CaseDef) {
+ val CaseDef(pat, guard, body) = tree
+ print("case ")
+ def patConstr(pat: Tree): Tree = pat match {
+ case Apply(fn, args) => patConstr(fn)
+ case _ => pat
+ }
+
+ print(pat); printOpt(" if ", guard)
+ print(" => ", body)
+ }
+
+ protected def printFunction(tree: Function)(printValueParams: => Unit) {
+ val Function(vparams, body) = tree
+ print("(");
+ printValueParams
+ print(" => ", body, ")")
+ if (printIds && tree.symbol != null) print("#" + tree.symbol.id)
+ }
+
+ protected def printSuper(tree: Super, resultName: => String) {
+ val Super(This(qual), mix) = tree
+ if (qual.nonEmpty || tree.symbol != NoSymbol) print(resultName + ".")
+ print("super")
+ if (mix.nonEmpty) print(s"[$mix]")
+ }
+
+ protected def printThis(tree: This, resultName: => String) {
+ val This(qual) = tree
+ if (qual.nonEmpty) print(resultName + ".")
+ print("this")
+ }
+
+ protected def printAnnotated(tree: Annotated)(printArg: => Unit) {
+ val Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), atree) = tree
+
+ def printAnnot() {
+ print("@", tpt)
+ if (args.nonEmpty)
+ printRow(args, "(", ",", ")")
+ }
+ printArg
+ printAnnot()
+ }
+
+ override def printTree(tree: Tree) {
+ parentsStack.push(tree)
+ tree match {
+ case cl @ ClassDef(mods, name, tparams, impl) =>
+ if (mods.isJavaDefined) super.printTree(cl)
+ printAnnotations(cl)
+ //traits
+ val clParents: List[Tree] = if (mods.isTrait) {
+ // avoid abstract modifier for traits
+ printModifiers(tree, mods &~ ABSTRACT)
+ print("trait ", printedName(name))
+ printTypeParams(tparams)
+
+ val build.SyntacticTraitDef(_, _, _, _, parents, _, _) = tree
+ parents
+ //classes
+ } else {
+ printModifiers(tree, mods)
+ print("class ", printedName(name))
+ printTypeParams(tparams)
+
+ val build.SyntacticClassDef(_, _, _, ctorMods, vparamss, earlyDefs, parents, selfType, body) = cl
+
+ //constructor's modifier
+ if (ctorMods.hasFlag(AccessFlags)) {
+ print(" ")
+ printModifiers(ctorMods, primaryCtorParam = false)
+ }
+
+ def printConstrParams(ts: List[ValDef]) {
+ parenthesize() {
+ printImplicitInParamsList(ts)
+ printSeq(ts)(printParam(_, primaryCtorParam = true))(print(", "))
+ }
+ }
+ //constructor's params processing (don't print single empty constructor param list)
+ vparamss match {
+ case Nil | List(Nil) if (!mods.isCase && !ctorMods.hasFlag(AccessFlags)) =>
+ case _ => vparamss foreach printConstrParams
+ }
+ parents
+ }
+
+ //get trees without default classes and traits (when they are last)
+ val printedParents = removeDefaultTypesFromList(clParents)()(if (mods.hasFlag(CASE)) defaultTraitsForCase else Nil)
+ print(if (mods.isDeferred) "<: " else if (printedParents.nonEmpty) " extends " else "", impl)
+
+ case pd @ PackageDef(packaged, stats) =>
+ packaged match {
+ case Ident(name) if name == nme.EMPTY_PACKAGE_NAME =>
+ printSeq(stats) {
+ print(_)
+ } {
+ print(";");
+ println()
+ };
+ case _ =>
+ printPackageDef(pd, "\n")
+ }
+
+ case md @ ModuleDef(mods, name, impl) =>
+ printAnnotations(md)
+ printModifiers(tree, mods)
+ val Template(parents, self, methods) = impl
+ val parWithoutAnyRef = removeDefaultClassesFromList(parents)
+ print("object " + printedName(name), if (parWithoutAnyRef.nonEmpty) " extends " else "", impl)
+
+ case vd @ ValDef(mods, name, tp, rhs) =>
+ printValDef(vd, printedName(name)) {
+ //place space after symbolic def name (val *: Unit does not compile)
+ printOpt(s"${blankForName(name)}: ", tp)
+ } {
+ if (!mods.isDeferred) print(" = ", if (rhs.isEmpty) "_" else rhs)
+ }
+
+ case dd @ DefDef(mods, name, tparams, vparamss, tp, rhs) =>
+ printDefDef(dd, printedName(name)) {
+ if (tparams.isEmpty && (vparamss.isEmpty || vparamss(0).isEmpty)) print(blankForName(name))
+ printOpt(": ", tp)
+ } {
+ printOpt(" = " + (if (mods.isMacro) "macro " else ""), rhs)
+ }
+
+ case td @ TypeDef(mods, name, tparams, rhs) =>
+ printTypeDef(td, printedName(name))
+
+ case LabelDef(name, params, rhs) =>
+ if (name.startsWith(nme.WHILE_PREFIX)) {
+ val If(cond, thenp, elsep) = rhs
+ print("while (", cond, ") ")
+ val Block(list, wh) = thenp
+ printColumn(list, "", ";", "")
+ } else if (name.startsWith(nme.DO_WHILE_PREFIX)) {
+ val Block(bodyList, ifCond @ If(cond, thenp, elsep)) = rhs
+ print("do ")
+ printColumn(bodyList, "", ";", "")
+ print(" while (", cond, ") ")
+ } else {
+ print(printedName(name)); printLabelParams(params);
+ printBlock(rhs)
+ }
+
+ case imp @ Import(expr, selectors) =>
+ printImport(imp, resolveSelect(expr))
+
+ case Template(parents, self, body) =>
+ val printedParents =
+ currentParent map {
+ case _: CompoundTypeTree => parents
+ case ClassDef(mods, name, _, _) if mods.isCase => removeDefaultTypesFromList(parents)()(List(tpnme.Product, tpnme.Serializable))
+ case _ => removeDefaultClassesFromList(parents)
+ } getOrElse (parents)
+
+ val primaryCtr = treeInfo.firstConstructor(body)
+ val ap: Option[Apply] = primaryCtr match {
+ case DefDef(_, _, _, _, _, Block(ctBody, _)) =>
+ val earlyDefs = treeInfo.preSuperFields(ctBody) ::: body.filter {
+ case td: TypeDef => treeInfo.isEarlyDef(td)
+ case _ => false
+ }
+ if (earlyDefs.nonEmpty) {
+ print("{")
+ printColumn(earlyDefs, "", ";", "")
+ print("} " + (if (printedParents.nonEmpty) "with " else ""))
+ }
+ ctBody collectFirst {
+ case apply: Apply => apply
+ }
+ case _ => None
+ }
+
+ if (printedParents.nonEmpty) {
+ val (clParent :: traits) = printedParents
+ print(clParent)
+
+ val constrArgss = ap match {
+ case Some(treeInfo.Applied(_, _, argss)) => argss
+ case _ => Nil
+ }
+ printArgss(constrArgss)
+ if (traits.nonEmpty) {
+ printRow(traits, " with ", " with ", "")
+ }
+ }
+ /* Remove primary constr def and constr val and var defs
+ * right contains all constructors
+ */
+ val (left, right) = body.filter {
+ //remove valdefs defined in constructor and presuper vals
+ case vd: ValDef => !vd.mods.isParamAccessor && !treeInfo.isEarlyValDef(vd)
+ //remove $this$ from traits
+ case dd: DefDef => dd.name != nme.MIXIN_CONSTRUCTOR
+ case td: TypeDef => !treeInfo.isEarlyDef(td)
+ case EmptyTree => false
+ case _ => true
+ } span {
+ case dd: DefDef => dd.name != nme.CONSTRUCTOR
+ case _ => true
+ }
+ val modBody = left ::: right.drop(1)
+ val showBody = !(modBody.isEmpty && (self == noSelfType || self.isEmpty))
+ if (showBody) {
+ if (self.name != nme.WILDCARD) {
+ print(" { ", self.name);
+ printOpt(": ", self.tpt);
+ print(" =>")
+ } else if (self.tpt.nonEmpty) {
+ print(" { _ : ", self.tpt, " =>")
+ } else {
+ print(" {")
+ }
+ printColumn(modBody, "", ";", "}")
+ }
+
+ case Block(stats, expr) => super.printTree(tree)
+
+ case Match(selector, cases) =>
+ /* Insert braces if match is inner
+ * make this function available for other cases
+ * passing required type for checking
+ */
+ def insertBraces(body: => Unit) {
+ if (parentsStack.nonEmpty && parentsStack.tail.exists(_.isInstanceOf[Match])) {
+ print("(")
+ body
+ print(")")
+ } else body
+ }
+
+ val printParentheses = needsParentheses(selector)(insideLabelDef = false)
+ tree match {
+ case Match(EmptyTree, cs) =>
+ printColumn(cases, "{", "", "}")
+ case _ =>
+ insertBraces {
+ parenthesize(printParentheses)(print(selector))
+ printColumn(cases, " match {", "", "}")
+ }
+ }
+
+ case cd @ CaseDef(pat, guard, body) =>
+ printCaseDef(cd)
+
+ case Star(elem) =>
+ print(elem, "*")
+
+ case Bind(name, t) =>
+ if (t == EmptyTree) print("(", printedName(name), ")")
+ else if (t.exists(_.isInstanceOf[Star])) print(printedName(name), " @ ", t)
+ else print("(", printedName(name), " @ ", t, ")")
+
+ case f @ Function(vparams, body) =>
+ //parentheses are not allowed for val a: Int => Int = implicit x => x
+ val printParentheses = vparams match {
+ case head :: _ => !head.mods.isImplicit
+ case _ => true
+ }
+ printFunction(f)(printValueParams(vparams, inParentheses = printParentheses))
+
+ case Typed(expr, tp) =>
+ tp match {
+ case Function(List(), EmptyTree) => print("(", expr, " _)") //func _
+ //parenteses required when (a match {}) : Type
+ case _ => print("((", expr, "): ", tp, ")")
+ }
+
+ case Apply(fun, vargs) =>
+ tree match {
+ //processing methods ending on colons (x \: list)
+ case Apply(Block(l1 @ List(sVD: ValDef), a1 @ Apply(Select(_, methodName), l2 @ List(Ident(iVDName)))), l3)
+ if sVD.mods.isSynthetic && treeInfo.isLeftAssoc(methodName) && sVD.name == iVDName =>
+ val printBlock = Block(l1, Apply(a1, l3))
+ print(printBlock)
+ case Apply(tree1, _) if (needsParentheses(tree1)(insideAnnotated = false)) =>
+ parenthesize()(print(fun)); printRow(vargs, "(", ", ", ")")
+ case _ => super.printTree(tree)
+ }
+
+ case st @ Super(This(qual), mix) =>
+ printSuper(st, printedName(qual))
+
+ case th @ This(qual) =>
+ printThis(th, printedName(qual))
+
+ case Select(qual @ New(tpe), name) =>
+ print(qual)
+
+ case Select(qualifier, name) => {
+ val printParentheses = needsParentheses(qualifier)(insideAnnotated = false) || isIntLitWithDecodedOp(qualifier, name)
+ if (printParentheses) print("(", resolveSelect(qualifier), ").", printedName(name))
+ else print(resolveSelect(qualifier), ".", printedName(name))
+ }
+
+ case id @ Ident(name) =>
+ if (name.nonEmpty) {
+ if (name == nme.dollarScope) {
+ print(s"scala.xml.${nme.TopScope}")
+ } else {
+ val str = printedName(name)
+ val strIsBackquoted = str.startsWith("`") && str.endsWith("`")
+ print(if (id.isBackquoted && !strIsBackquoted) "`" + str + "`" else str)
+ }
+ } else {
+ print("")
+ }
+
+ case l @ Literal(x) =>
+ x match {
+ case Constant(v: String) if {
+ val strValue = x.stringValue
+ strValue.contains("\n") && strValue.contains("\"\"\"") && strValue.size > 1
+ } =>
+ val splitValue = x.stringValue.split('\n'.toString).toList
+ val multilineStringValue = if (x.stringValue.endsWith("\n")) splitValue :+ "" else splitValue
+ val trQuotes = "\"\"\""
+ print(trQuotes); printSeq(multilineStringValue) { print(_) } { print("\n") }; print(trQuotes)
+ case _ =>
+ //processing Float constants
+ val printValue = x.escapedStringValue + (if (x.value.isInstanceOf[Float]) "F" else "")
+ print(printValue)
+ }
+
+ case an @ Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) =>
+ printAnnotated(an) {
+ val printParentheses = needsParentheses(tree)()
+ parenthesize(printParentheses) { print(tree) }; print(if (tree.isType) " " else ": ")
+ }
+
+ case SelectFromTypeTree(qualifier, selector) =>
+ print("(", qualifier, ")#", blankForOperatorName(selector), printedName(selector))
+
+ case AppliedTypeTree(tp, args) =>
+ //it's possible to have (=> String) => String type but Function1[=> String, String] is not correct
+ val containsByNameTypeParam = args exists treeInfo.isByNameParamType
+
+ if (containsByNameTypeParam) {
+ print("(")
+ printRow(args.init, "(", ", ", ")")
+ print(" => ", args.last, ")")
+ } else {
+ if (treeInfo.isRepeatedParamType(tree) && args.nonEmpty) {
+ print(args(0), "*")
+ } else if (treeInfo.isByNameParamType(tree)) {
+ print("=> ", if (args.isEmpty) "()" else args(0))
+ } else
+ super.printTree(tree)
+ }
+
+ case ExistentialTypeTree(tpt, whereClauses) =>
+ print("(", tpt);
+ printColumn(whereClauses, " forSome { ", ";", "})")
+
+ case EmptyTree =>
+
+ case tree => super.printTree(tree)
+ }
+ parentsStack.pop()
+ }
+ }
/** Hook for extensions */
def xprintTree(treePrinter: TreePrinter, tree: Tree) =
treePrinter.print(tree.productPrefix+tree.productIterator.mkString("(", ", ", ")"))
+ def newCodePrinter(writer: PrintWriter): TreePrinter = new ParsedTreePrinter(writer)
def newTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer)
def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream))
def newTreePrinter(): TreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter))