summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-01-15 08:02:35 -0800
committerJason Zaugg <jzaugg@gmail.com>2014-01-15 08:02:35 -0800
commit07e823ad9710734092c81fa7734e38bbd4fe2efa (patch)
treee86f67f9406604a8613bb01a93a3f5809076f97c
parentdb8b599fc6f9c66f37a653e65fd31c9b0cd344ce (diff)
parentd680d23947778a963ec23580efccbf2527f3a97c (diff)
downloadscala-07e823ad9710734092c81fa7734e38bbd4fe2efa.tar.gz
scala-07e823ad9710734092c81fa7734e38bbd4fe2efa.tar.bz2
scala-07e823ad9710734092c81fa7734e38bbd4fe2efa.zip
Merge pull request #3321 from VladimirNik/sprinter
Add tree-based code generation
-rw-r--r--src/reflect/scala/reflect/api/Printers.scala19
-rw-r--r--src/reflect/scala/reflect/internal/Printers.scala795
-rw-r--r--test/files/run/reify_ann3.check4
-rw-r--r--test/junit/scala/reflect/internal/PrintersTest.scala815
4 files changed, 1502 insertions, 131 deletions
diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala
index 1e0854d171..5bc92d3893 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 showCode(tree: Tree) = render(tree, newCodePrinter)
+
+ /**
+ * Hook to define what `showCode(...)` 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 424e73dce8..8b72f98e4d 100644
--- a/src/reflect/scala/reflect/internal/Printers.scala
+++ b/src/reflect/scala/reflect/internal/Printers.scala
@@ -17,8 +17,6 @@ trait Printers extends api.Printers { self: SymbolTable =>
//nsc import treeInfo.{ IsTrue, IsFalse }
- final val showOuterTests = false
-
/** Adds backticks if the name is a scala keyword. */
def quotedName(name: Name, decode: Boolean): String = {
val s = if (decode) name.decode else name.toString
@@ -53,8 +51,8 @@ trait Printers extends api.Printers { self: SymbolTable =>
*/
def backquotedPath(t: Tree): String = {
t match {
- case Select(qual, name) if name.isTermName => "%s.%s".format(backquotedPath(qual), symName(t, name))
- case Select(qual, name) if name.isTypeName => "%s#%s".format(backquotedPath(qual), symName(t, name))
+ case Select(qual, name) if name.isTermName => s"${backquotedPath(qual)}.${symName(t, name)}"
+ case Select(qual, name) if name.isTypeName => s"${backquotedPath(qual)}#${symName(t, name)}"
case Ident(name) => symName(t, name)
case _ => t.toString
}
@@ -76,7 +74,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
def printPosition(tree: Tree) = if (printPositions) print(tree.pos.show)
- def println() {
+ def println() = {
out.println()
while (indentMargin > indentString.length())
indentString += indentString
@@ -84,116 +82,221 @@ trait Printers extends api.Printers { self: SymbolTable =>
out.write(indentString, 0, indentMargin)
}
- def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit) {
+ def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit): Unit =
ls match {
case List() =>
case List(x) => printelem(x)
case x :: rest => printelem(x); printsep; printSeq(rest)(printelem)(printsep)
}
- }
- def printColumn(ts: List[Tree], start: String, sep: String, end: String) {
+ def printColumn(ts: List[Tree], start: String, sep: String, end: String) = {
print(start); indent(); println()
printSeq(ts){print(_)}{print(sep); println()}; undent(); println(); print(end)
}
- def printRow(ts: List[Tree], start: String, sep: String, end: String) {
+ def printRow(ts: List[Tree], start: String, sep: String, end: String): Unit = {
print(start); printSeq(ts){print(_)}{print(sep)}; print(end)
}
- def printRow(ts: List[Tree], sep: String) { printRow(ts, "", sep, "") }
+ def printRow(ts: List[Tree], sep: String): Unit = printRow(ts, "", sep, "")
- def printTypeParams(ts: List[TypeDef]) {
- if (!ts.isEmpty) {
+ def printTypeParams(ts: List[TypeDef]): Unit =
+ if (ts.nonEmpty) {
print("["); printSeq(ts){ t =>
printAnnotations(t)
+ if (t.mods.hasFlag(CONTRAVARIANT)) {
+ print("-")
+ } else if (t.mods.hasFlag(COVARIANT)) {
+ print("+")
+ }
printParam(t)
}{print(", ")}; print("]")
}
- }
- def printLabelParams(ps: List[Ident]) {
+ def printLabelParams(ps: List[Ident]) = {
print("(")
printSeq(ps){printLabelParam}{print(", ")}
print(")")
}
- def printLabelParam(p: Ident) {
+ def printLabelParam(p: Ident) = {
print(symName(p, p.name)); printOpt(": ", TypeTree() setType p.tpe)
}
- def printValueParams(ts: List[ValDef]) {
- print("(")
- if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, "")
- printSeq(ts){printParam}{print(", ")}
- print(")")
+ 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 = true): Unit =
+ parenthesize(inParentheses){
+ printImplicitInParamsList(ts)
+ printSeq(ts){printParam}{print(", ")}
+ }
- def printParam(tree: Tree) {
+ def printParam(tree: Tree) =
tree match {
- case ValDef(mods, name, tp, rhs) =>
+ case vd @ ValDef(mods, name, tp, rhs) =>
printPosition(tree)
- printAnnotations(tree)
+ printAnnotations(vd)
print(symName(tree, name)); printOpt(": ", tp); printOpt(" = ", rhs)
case TypeDef(mods, name, tparams, rhs) =>
printPosition(tree)
print(symName(tree, name))
printTypeParams(tparams); print(rhs)
}
- }
- def printBlock(tree: Tree) {
+ def printBlock(tree: Tree) =
tree match {
case Block(_, _) =>
print(tree)
case _ =>
printColumn(List(tree), "{", ";", "}")
}
- }
private def symFn[T](tree: Tree, f: Symbol => T, orElse: => T): T = tree.symbol match {
- case null | NoSymbol => orElse
- case sym => f(sym)
+ case null | NoSymbol => orElse
+ case sym => f(sym)
}
private def ifSym(tree: Tree, p: Symbol => Boolean) = symFn(tree, p, false)
- def printOpt(prefix: String, tree: Tree) {
- if (!tree.isEmpty) { print(prefix, tree) }
- }
+ def printOpt(prefix: String, tree: Tree) = if (tree.nonEmpty) { print(prefix, tree) }
def printModifiers(tree: Tree, mods: Modifiers): Unit = printFlags(
- if (tree.symbol == NoSymbol) mods.flags else tree.symbol.flags, "" + (
- if (tree.symbol == NoSymbol) mods.privateWithin
- else if (tree.symbol.hasAccessBoundary) tree.symbol.privateWithin.name
- else ""
+ if (tree.symbol == NoSymbol) mods.flags else tree.symbol.flags, "" + (
+ if (tree.symbol == NoSymbol) mods.privateWithin
+ else if (tree.symbol.hasAccessBoundary) tree.symbol.privateWithin.name
+ else ""
)
)
- def printFlags(flags: Long, privateWithin: String) {
+ def printFlags(flags: Long, privateWithin: String) = {
val mask: Long = if (settings.debug) -1L else PrintableFlags
val s = flagsToString(flags & mask, privateWithin)
if (s != "") print(s + " ")
}
- def printAnnotations(tree: Tree) {
+ def printAnnotations(tree: MemberDef) = {
// SI-5885: by default this won't print annotations of not yet initialized symbols
val annots = tree.symbol.annotations match {
- case Nil => tree.asInstanceOf[MemberDef].mods.annotations
+ case Nil => tree.mods.annotations
case anns => anns
}
- annots foreach (annot => print("@"+annot+" "))
+ annots foreach (annot => print(s"@$annot "))
}
private var currentOwner: Symbol = NoSymbol
private var selectorType: Type = NoType
+
+ 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")
+ }
- def printTree(tree: Tree) {
+ def printTree(tree: Tree) = {
tree match {
case EmptyTree =>
print("<empty>")
- case ClassDef(mods, name, tparams, impl) =>
- printAnnotations(tree)
+ case cd @ ClassDef(mods, name, tparams, impl) =>
+ printAnnotations(cd)
printModifiers(tree, mods)
val word =
if (mods.isTrait) "trait"
@@ -204,81 +307,45 @@ trait Printers extends api.Printers { self: SymbolTable =>
printTypeParams(tparams)
print(if (mods.isDeferred) " <: " else " extends ", impl)
- case PackageDef(packaged, stats) =>
- printAnnotations(tree)
- print("package ", packaged); printColumn(stats, " {", ";", "}")
+ case pd @ PackageDef(packaged, stats) =>
+ printPackageDef(pd, ";")
- case ModuleDef(mods, name, impl) =>
- printAnnotations(tree)
+ case md @ ModuleDef(mods, name, impl) =>
+ printAnnotations(md)
printModifiers(tree, mods)
print("object " + symName(tree, name), " extends ", impl)
- case ValDef(mods, name, tp, rhs) =>
- printAnnotations(tree)
- printModifiers(tree, mods)
- print(if (mods.isMutable) "var " else "val ", symName(tree, name))
- printOpt(": ", tp)
- if (!mods.isDeferred)
- print(" = ", if (rhs.isEmpty) "_" else rhs)
+ case vd @ ValDef(mods, name, tp, rhs) =>
+ printValDef(vd, symName(tree, name))(printOpt(": ", tp)) {
+ if (!mods.isDeferred) print(" = ", if (rhs.isEmpty) "_" else rhs)
+ }
- case DefDef(mods, name, tparams, vparamss, tp, rhs) =>
- printAnnotations(tree)
- printModifiers(tree, mods)
- print("def " + symName(tree, name))
- printTypeParams(tparams); vparamss foreach printValueParams
- printOpt(": ", tp); printOpt(" = ", rhs)
+ case dd @ DefDef(mods, name, tparams, vparamss, tp, rhs) =>
+ printDefDef(dd, symName(tree, name))(printOpt(": ", tp))(printOpt(" = ", rhs))
- case TypeDef(mods, name, tparams, rhs) =>
- if (mods hasFlag (PARAM | DEFERRED)) {
- printAnnotations(tree)
- printModifiers(tree, mods); print("type "); printParam(tree)
- } else {
- printAnnotations(tree)
- printModifiers(tree, mods); print("type " + symName(tree, name))
- printTypeParams(tparams); printOpt(" = ", rhs)
- }
+ case td @ TypeDef(mods, name, tparams, rhs) =>
+ printTypeDef(td, symName(tree, name))
case LabelDef(name, params, rhs) =>
print(symName(tree, name)); printLabelParams(params); printBlock(rhs)
- case Import(expr, selectors) =>
- // Is this selector remapping a name (i.e, {name1 => name2})
- def isNotRemap(s: ImportSelector) : Boolean = (s.name == nme.WILDCARD || s.name == s.rename)
- def selectorToString(s: ImportSelector): String = {
- val from = quotedName(s.name)
- if (isNotRemap(s)) from
- else from + "=>" + quotedName(s.rename)
- }
- print("import ", backquotedPath(expr), ".")
- selectors match {
- case List(s) =>
- // If there is just one selector and it is not remapping a name, no braces are needed
- if (isNotRemap(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("{", ", ", "}"))
- }
+ case imp @ Import(expr, _) =>
+ printImport(imp, backquotedPath(expr))
- case Template(parents, self, body) =>
+ case Template(parents, self, body) =>
val currentOwner1 = currentOwner
if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner
-// if (parents exists isReferenceToAnyVal) {
-// print("AnyVal")
-// }
-// else {
printRow(parents, " with ")
- if (!body.isEmpty) {
+ if (body.nonEmpty) {
if (self.name != nme.WILDCARD) {
print(" { ", self.name); printOpt(": ", self.tpt); print(" => ")
- } else if (!self.tpt.isEmpty) {
+ } else if (self.tpt.nonEmpty) {
print(" { _ : ", self.tpt, " => ")
} else {
print(" {")
}
printColumn(body, "", ";", "}")
}
-// }
currentOwner = currentOwner1
case Block(stats, expr) =>
@@ -290,18 +357,8 @@ trait Printers extends api.Printers { self: SymbolTable =>
print(selector); printColumn(cases, " match {", "", "}")
selectorType = selectorType1
- case CaseDef(pat, guard, body) =>
- print("case ")
- def patConstr(pat: Tree): Tree = pat match {
- case Apply(fn, args) => patConstr(fn)
- case _ => pat
- }
- if (showOuterTests &&
- needsOuterTest(
- patConstr(pat).tpe.finalResultType, selectorType, currentOwner))
- print("???")
- print(pat); printOpt(" if ", guard)
- print(" => ", body)
+ case cd @ CaseDef(pat, guard, body) =>
+ printCaseDef(cd)
case Alternative(trees) =>
printRow(trees, "(", "| ", ")")
@@ -318,9 +375,8 @@ trait Printers extends api.Printers { self: SymbolTable =>
case ArrayValue(elemtpt, trees) =>
print("Array[", elemtpt); printRow(trees, "]{", ", ", "}")
- case Function(vparams, body) =>
- print("("); printValueParams(vparams); print(" => ", body, ")")
- if (printIds && tree.symbol != null) print("#"+tree.symbol.id)
+ case f @ Function(vparams, body) =>
+ printFunction(f)(printValueParams(vparams))
case Assign(lhs, rhs) =>
print(lhs, " = ", rhs)
@@ -331,7 +387,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
case If(cond, thenp, elsep) =>
print("if (", cond, ")"); indent(); println()
print(thenp); undent()
- if (!elsep.isEmpty) {
+ if (elsep.nonEmpty) {
println(); print("else"); indent(); println(); print(elsep); undent()
}
@@ -340,7 +396,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
case Try(block, catches, finalizer) =>
print("try "); printBlock(block)
- if (!catches.isEmpty) printColumn(catches, " catch {", "", "}")
+ if (catches.nonEmpty) printColumn(catches, " catch {", "", "}")
printOpt(" finally ", finalizer)
case Throw(expr) =>
@@ -362,22 +418,18 @@ trait Printers extends api.Printers { self: SymbolTable =>
print("<apply-dynamic>(", qual, "#", tree.symbol.nameString)
printRow(vargs, ", (", ", ", "))")
- case Super(This(qual), mix) =>
- if (!qual.isEmpty || tree.symbol != NoSymbol) print(symName(tree, qual) + ".")
- print("super")
- if (!mix.isEmpty)
- print("[" + mix + "]")
+ case st @ Super(This(qual), mix) =>
+ printSuper(st, symName(tree, qual))
case Super(qual, mix) =>
print(qual, ".super")
- if (!mix.isEmpty)
+ if (mix.nonEmpty)
print("[" + mix + "]")
- case This(qual) =>
- if (!qual.isEmpty) print(symName(tree, qual) + ".")
- print("this")
+ case th @ This(qual) =>
+ printThis(th, symName(tree, qual))
- case Select(qual @ New(tpe), name) if !settings.debug =>
+ case Select(qual: New, name) if !settings.debug =>
print(qual)
case Select(qualifier, name) =>
@@ -400,10 +452,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
print(tree.tpe.toString)
}
- case Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) =>
+ case an @ Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) =>
def printAnnot() {
print("@", tpt)
- if (!args.isEmpty)
+ if (args.nonEmpty)
printRow(args, "(", ",", ")")
}
print(tree, if (tree.isType) " " else ": ")
@@ -435,11 +487,11 @@ trait Printers extends api.Printers { self: SymbolTable =>
print(tpt)
printColumn(whereClauses, " forSome { ", ";", "}")
-// SelectFromArray is no longer visible in scala.reflect.internal.
-// eliminated until we figure out what we will do with both Printers and
-// SelectFromArray.
-// case SelectFromArray(qualifier, name, _) =>
-// print(qualifier); print(".<arr>"); print(symName(tree, name))
+ // SelectFromArray is no longer visible in scala.reflect.internal.
+ // eliminated until we figure out what we will do with both Printers and
+ // SelectFromArray.
+ // case SelectFromArray(qualifier, name, _) =>
+ // print(qualifier); print(".<arr>"); print(symName(tree, name))
case tree =>
xprintTree(this, tree)
@@ -459,11 +511,496 @@ trait Printers extends api.Printers { self: SymbolTable =>
out.print(if (arg == null) "null" else arg.toString)
}
}
+
+ // it's the 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
+
+ // TODO: 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 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 _ => showCode(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): Unit = {
+ 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): Unit =
+ 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): Unit = {
+ 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: MemberDef) = {
+ val annots = tree.mods.annotations
+ annots foreach {annot => printAnnot(annot); print(" ")}
+ }
+
+ protected def printAnnot(tree: Tree) = {
+ tree match {
+ case treeInfo.Applied(core, _, argss) =>
+ print("@")
+ core match {
+ case Select(New(tree), _) => print(tree)
+ case _ =>
+ }
+ printArgss(argss)
+ case _ => super.printTree(tree)
+ }
+ }
+
+ override def printTree(tree: Tree): Unit = {
+ 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]): Unit = {
+ 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, _) =>
+ 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): 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 _
+ // parentheses 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, 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(ap, tree) =>
+ val printParentheses = needsParentheses(tree)()
+ parenthesize(printParentheses) { print(tree) }; print(if (tree.isType) " " else ": ")
+ printAnnot(ap)
+
+ 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))
diff --git a/test/files/run/reify_ann3.check b/test/files/run/reify_ann3.check
index d4cf660758..4f1c61cf0e 100644
--- a/test/files/run/reify_ann3.check
+++ b/test/files/run/reify_ann3.check
@@ -1,5 +1,5 @@
{
- class Tree[A, B] extends AnyRef {
+ class Tree[A, +B] extends AnyRef {
@new inline @getter() final <paramaccessor> val key: A = _;
def <init>(key: A) = {
super.<init>();
@@ -9,7 +9,7 @@
()
}
{
- class Tree[A, B] extends AnyRef {
+ class Tree[A, +B] extends AnyRef {
final <paramaccessor> private[this] val key: A = _;
@inline @scala.annotation.meta.getter final <stable> <accessor> <paramaccessor> def key: A = Tree.this.key;
def <init>(key: A): Tree[A,B] = {
diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala
new file mode 100644
index 0000000000..53ea3fd8a3
--- /dev/null
+++ b/test/junit/scala/reflect/internal/PrintersTest.scala
@@ -0,0 +1,815 @@
+package scala.reflect.internal
+
+import org.junit.Test
+import org.junit.Assert._
+import scala.tools.reflect._
+import scala.reflect.runtime.universe._
+import scala.reflect.runtime.{currentMirror=>cm}
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(classOf[JUnit4])
+class PrintersTest extends BasePrintTests
+ with ClassPrintTests
+ with TraitPrintTests
+ with ValAndDefPrintTests
+ with QuasiTreesPrintTests
+ with PackagePrintTests
+
+object PrinterHelper {
+ val toolbox = cm.mkToolBox()
+ def assertPrintedCode(code: String, tree: Tree = EmptyTree) = {
+ val toolboxTree =
+ try{
+ toolbox.parse(code)
+ } catch {
+ case e:scala.tools.reflect.ToolBoxError => throw new Exception(e.getMessage + ": " + code)
+ }
+ if (tree ne EmptyTree) assertEquals("using quasiquote or given tree"+"\n", code.trim, showCode(tree))
+ else assertEquals("using toolbox parser", code.trim, showCode(toolboxTree))
+ }
+
+ implicit class StrContextStripMarginOps(val stringContext: StringContext) extends util.StripMarginInterpolator
+}
+
+import PrinterHelper._
+
+trait BasePrintTests {
+ @Test def testIdent = assertPrintedCode("*", Ident("*"))
+
+ @Test def testConstant1 = assertPrintedCode("\"*\"", Literal(Constant("*")))
+
+ @Test def testConstant2 = assertPrintedCode("42", Literal(Constant(42)))
+
+ @Test def testConstantFloat = assertPrintedCode("42.0F", Literal(Constant(42f)))
+
+ @Test def testConstantDouble = assertPrintedCode("42.0", Literal(Constant(42d)))
+
+ @Test def testConstantLong = assertPrintedCode("42L", Literal(Constant(42l)))
+
+ @Test def testOpExpr = assertPrintedCode("(5).+(4)")
+
+ @Test def testName1 = assertPrintedCode("class test")
+
+ @Test def testName2 = assertPrintedCode("class *")
+
+ @Test def testName4 = assertPrintedCode("class `a*`")
+
+ @Test def testName5 = assertPrintedCode("val :::: = 1")
+
+ @Test def testName6 = assertPrintedCode("val `::::t` = 1")
+
+ @Test def testName7 = assertPrintedCode("""class \/""")
+
+ @Test def testName8 = assertPrintedCode("""class \\\\""")
+
+ @Test def testName9 = assertPrintedCode("""class test_\/""")
+
+ @Test def testName10 = assertPrintedCode("""class `*_*`""")
+
+ @Test def testName11 = assertPrintedCode("""class `a_*`""")
+
+ @Test def testName12 = assertPrintedCode("""class `*_a`""")
+
+ @Test def testName13 = assertPrintedCode("""class a_a""")
+
+ @Test def testName14 = assertPrintedCode("val x$11 = 5")
+
+ @Test def testName15 = assertPrintedCode("class `[]`")
+
+ @Test def testName16 = assertPrintedCode("class `()`")
+
+ @Test def testName17 = assertPrintedCode("class `{}`")
+
+ @Test def testName18 = assertPrintedCode("class <>")
+
+ @Test def testName19 = assertPrintedCode("""class `class`""")
+
+ @Test def testName20 = assertPrintedCode("""class `test name`""")
+
+ @Test def testIfExpr1 = assertPrintedCode(sm"""
+ |if (a)
+ | ((expr1): Int)
+ |else
+ | ((expr2): Int)""")
+
+ @Test def testIfExpr2 = assertPrintedCode(sm"""
+ |(if (a)
+ | {
+ | expr1;
+ | ()
+ | }
+ |else
+ | {
+ | expr2;
+ | ()
+ | }).toString""")
+
+ @Test def testIfExpr3 = assertPrintedCode(sm"""
+ |(if (a)
+ | {
+ | expr1;
+ | ()
+ | }
+ |else
+ | {
+ | expr2;
+ | ()
+ | }).method1().method2()""")
+
+ //val x = true && true && false.!
+ @Test def testBooleanExpr1 = assertPrintedCode("val x = true.&&(true).&&(false.!)")
+
+ //val x = true && !(true && false)
+ @Test def testBooleanExpr2 = assertPrintedCode("val x = true.&&(true.&&(false).`unary_!`)")
+
+ @Test def testNewExpr1 = assertPrintedCode("new foo()")
+
+ //new foo { test }
+ @Test def testNewExpr2 = assertPrintedCode(sm"""
+ |{
+ | final class $$anon extends foo {
+ | test
+ | };
+ | new $$anon()
+ |}""")
+
+ @Test def testNewExpr3 = assertPrintedCode("new foo[t]()")
+
+ @Test def testNewExpr4 = assertPrintedCode("new foo(x)")
+
+ @Test def testNewExpr5 = assertPrintedCode("new foo[t](x)")
+
+ //new foo[t](x) { () }
+ @Test def testNewExpr6 = assertPrintedCode(sm"""
+ |{
+ | final class $$anon extends foo[t](x) {
+ | ()
+ | };
+ | new $$anon()
+ |}""")
+
+ //new foo with bar
+ @Test def testNewExpr7 = assertPrintedCode(sm"""
+ |{
+ | final class $$anon extends foo with bar;
+ | new $$anon()
+ |}""")
+
+ //new { anonymous }
+ @Test def testNewExpr8 = assertPrintedCode(sm"""
+ |{
+ | final class $$anon {
+ | anonymous
+ | };
+ | new $$anon()
+ |}""")
+
+ //new { val early = 1 } with Parent[Int] { body }
+ @Test def testNewExpr9 = assertPrintedCode(sm"""
+ |{
+ | final class $$anon extends {
+ | val early = 1
+ | } with Parent[Int] {
+ | body
+ | };
+ | new $$anon()
+ |}""")
+
+ //new Foo { self => }
+ @Test def testNewExpr10 = assertPrintedCode(sm"""
+ |{
+ | final class $$anon extends Foo { self =>
+ |
+ | };
+ | new $$anon()
+ |}""")
+
+ @Test def testReturn = assertPrintedCode("def test: Int = return 42")
+
+ @Test def testFunc1 = assertPrintedCode("List(1, 2, 3).map(((i: Int) => i.-(1)))")
+
+ //val sum: Seq[Int] => Int = _ reduceLeft (_+_)
+ @Test def testFunc2 = assertPrintedCode("val sum: _root_.scala.Function1[Seq[Int], Int] = ((x$1) => x$1.reduceLeft(((x$2, x$3) => x$2.+(x$3))))")
+
+ //List(1, 2, 3) map (_ - 1)
+ @Test def testFunc3 = assertPrintedCode("List(1, 2, 3).map(((x$1) => x$1.-(1)))")
+
+ @Test def testImport1 = assertPrintedCode("import scala.collection.mutable")
+
+ @Test def testImport2 = assertPrintedCode("import java.lang.{String=>Str}")
+
+ @Test def testImport3 = assertPrintedCode("import java.lang.{String=>Str, Object=>_, _}")
+
+ @Test def testImport4 = assertPrintedCode("import scala.collection._")
+}
+
+trait ClassPrintTests {
+ @Test def testClass = assertPrintedCode("class *")
+
+ @Test def testClassWithBody = assertPrintedCode(sm"""
+ |class X {
+ | def y = "test"
+ |}""")
+
+ @Test def testClassWithPublicParams = assertPrintedCode("class X(val x: Int, val s: String)")
+
+ @Test def testClassWithParams1 = assertPrintedCode("class X(x: Int, s: String)")
+
+ @Test def testClassWithParams2 = assertPrintedCode("class X(@test x: Int, s: String)")
+
+ @Test def testClassWithParams3 = assertPrintedCode("class X(implicit x: Int, s: String)")
+
+ @Test def testClassWithParams4 = assertPrintedCode("class X(implicit @test x: Int, s: String)")
+
+ @Test def testClassWithParams5 = assertPrintedCode("class X(override private[this] val x: Int, s: String) extends Y")
+
+ @Test def testClassWithParams6 = assertPrintedCode("class X(@test1 override private[this] val x: Int, @test2(param1 = 7) s: String) extends Y")
+
+ @Test def testClassWithParams7 = assertPrintedCode("class X protected (val x: Int, val s: String)")
+
+ @Test def testClassWithParams8 = assertPrintedCode("class X(var x: Int)")
+
+ @Test def testClassWithParams9 = assertPrintedCode("class X(var x: Int*)")
+
+ @Test def testClassWithByNameParam = assertPrintedCode("class X(x: => Int)")
+
+ @Test def testClassWithDefault = assertPrintedCode("class X(var x: Int = 5)")
+
+ @Test def testClassWithParams10 = assertPrintedCode("class X(protected[zzz] var x: Int)")
+
+ @Test def testClassWithParams11 = assertPrintedCode("class X(override var x: Int) extends F(x) with E(x)")
+
+ @Test def testClassWithParams12 = assertPrintedCode("class X(val y: Int)()(var z: Double)")
+
+ @Test def testClassWithImplicitParams = assertPrintedCode("class X(var i: Int)(implicit val d: Double, var f: Float)")
+
+ @Test def testClassWithEarly = assertPrintedCode(sm"""
+ |class X(var i: Int) extends {
+ | val a: String = i;
+ | type B
+ |} with Y""")
+
+ @Test def testClassWithThrow1 = assertPrintedCode(sm"""
+ |class Throw1 {
+ | throw new Exception("exception!")
+ |}""")
+
+ @Test def testClassWithThrow2 = assertPrintedCode(sm"""
+ |class Throw2 {
+ | var msg = " ";
+ | val e = new Exception(msg);
+ | throw e
+ |}""")
+
+ /*
+ class Test {
+ val (a, b) = (1, 2)
+ }
+ */
+ @Test def testClassWithAssignmentWithTuple1 = assertPrintedCode(sm"""
+ |class Test {
+ | private[this] val x$$1 = (scala.Tuple2(1, 2): @scala.unchecked) match {
+ | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2(a, b)
+ | };
+ | val a = x$$1._1;
+ | val b = x$$1._2
+ |}""")
+
+ /*
+ class Test {
+ val (a, b) = (1).->(2)
+ }
+ */
+ @Test def testClassWithAssignmentWithTuple2 = assertPrintedCode(sm"""
+ |class Test {
+ | private[this] val x$$1 = ((1).->(2): @scala.unchecked) match {
+ | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2(a, b)
+ | };
+ | val a = x$$1._1;
+ | val b = x$$1._2
+ |}""")
+
+ /*
+ class Test {
+ val List(one, three, five) = List(1,3,5)
+ }
+ */
+ @Test def testClassWithPatternMatchInAssignment = assertPrintedCode(sm"""
+ |class Test {
+ | private[this] val x$$1 = (List(1, 3, 5): @scala.unchecked) match {
+ | case List((one @ _), (three @ _), (five @ _)) => scala.Tuple3(one, three, five)
+ | };
+ | val one = x$$1._1;
+ | val three = x$$1._2;
+ | val five = x$$1._3
+ |}""")
+
+ //class A(l: List[_])
+ @Test def testClassWithExistentialParameter1 = assertPrintedCode(sm"""
+ |class Test(l: (List[_$$1] forSome {
+ | type _$$1
+ |}))""")
+
+ @Test def testClassWithExistentialParameter2 = assertPrintedCode(sm"""
+ |class B(l: (List[T] forSome {
+ | type T
+ |}))""")
+
+ @Test def testClassWithCompoundTypeTree = assertPrintedCode(sm"""
+ |{
+ | trait A;
+ | trait B;
+ | abstract class C(val a: A with B) {
+ | def method(x: A with B with C {
+ | val x: Float
+ | }): A with B
+ | };
+ | ()
+ |}""")
+
+ @Test def testClassWithSelectFromTypeTree = assertPrintedCode(sm"""
+ |{
+ | trait A {
+ | type T
+ | };
+ | class B(t: (A)#T);
+ | ()
+ |}""")
+
+ @Test def testImplicitClass = assertPrintedCode("implicit class X(protected[zzz] var x: Int)")
+
+ @Test def testAbstractClass = assertPrintedCode("abstract class X(protected[zzz] var x: Int)")
+
+ @Test def testCaseClassWithParams1 = assertPrintedCode("case class X(x: Int, s: String)")
+
+ @Test def testCaseClassWithParams2 = assertPrintedCode("case class X(protected val x: Int, s: String)")
+
+ @Test def testCaseClassWithParams3 = assertPrintedCode("case class X(implicit x: Int, s: String)")
+
+ @Test def testCaseClassWithParams4 = assertPrintedCode("case class X(override val x: Int, s: String) extends Y")
+
+ @Test def testCaseClassWithBody = assertPrintedCode(sm"""
+ |case class X() {
+ | def y = "test"
+ |}""")
+
+ @Test def testLocalClass = assertPrintedCode(sm"""
+ |def test = {
+ | class X(var a: Int) {
+ | def y = "test"
+ | };
+ | new X(5)
+ |}""")
+
+ @Test def testLocalCaseClass = assertPrintedCode(sm"""
+ |def test = {
+ | case class X(var a: Int) {
+ | def y = "test"
+ | };
+ | new X(5)
+ |}""")
+
+ @Test def testSuperInClass = assertPrintedCode(sm"""
+ |{
+ | trait Root {
+ | def r = "Root"
+ | };
+ | class X extends Root {
+ | def superX = super.r
+ | };
+ | class Y extends X with Root {
+ | class Inner {
+ | val myY = Y.super.r
+ | };
+ | def fromX = super[X].r;
+ | def fromRoot = super[Root].r
+ | };
+ | ()
+ |}""")
+
+ @Test def testThisInClass = assertPrintedCode(sm"""
+ |class Outer {
+ | class Inner {
+ | val outer = Root.this
+ | };
+ | val self = this
+ |}""")
+
+ @Test def testCaseClassWithParamsAndBody = assertPrintedCode(sm"""
+ |case class X(x: Int, s: String) {
+ | def y = "test"
+ |}""")
+
+ @Test def testObject = assertPrintedCode("object *")
+
+ @Test def testObjectWithBody = assertPrintedCode(sm"""
+ |object X {
+ | def y = "test"
+ |}""")
+
+ @Test def testObjectWithEarly1 = assertPrintedCode(sm"""
+ |object X extends {
+ | val early: T = v
+ |} with Bar""")
+
+ @Test def testObjectWithEarly2 = assertPrintedCode(sm"""
+ |object X extends {
+ | val early: T = v;
+ | type EarlyT = String
+ |} with Bar""")
+
+ @Test def testObjectWithSelf = assertPrintedCode(sm"""
+ |object Foo extends Foo { self =>
+ | body
+ |}""")
+
+ @Test def testObjectInh = assertPrintedCode("private[Y] object X extends Bar with Baz")
+
+ @Test def testObjectWithPatternMatch1 = assertPrintedCode(sm"""
+ |object PM1 {
+ | List(1, 2) match {
+ | case (i @ _) => i
+ | }
+ |}""")
+
+ @Test def testObjectWithPatternMatch2 = assertPrintedCode(sm"""
+ |object PM2 {
+ | List(1, 2).map({
+ | case (i @ _) if i.>(5) => i
+ | })
+ |}""")
+
+ //case i: Int => i
+ @Test def testObjectWithPatternMatch3 = assertPrintedCode(sm"""
+ |object PM3 {
+ | List(1, 2).map({
+ | case (i @ ((_): Int)) => i
+ | })
+ |}""")
+
+ //case a @ (i: Int) => i
+ @Test def testObjectWithPatternMatch4 = assertPrintedCode(sm"""
+ |object PM4 {
+ | List(1, 2).map({
+ | case (a @ (i @ ((_): Int))) => i
+ | })
+ |}""")
+
+ @Test def testObjectWithPatternMatch5 = assertPrintedCode(sm"""
+ |object PM5 {
+ | List(1, 2).map({
+ | case _ => 42
+ | })
+ |}""")
+
+ @Test def testObjectWithPatternMatch6 = assertPrintedCode(sm"""
+ |object PM6 {
+ | List(1, 2) match {
+ | case ::((x @ _), (xs @ _)) => x
+ | }
+ |}""")
+
+ @Test def testObjectWithPatternMatch7 = assertPrintedCode(sm"""
+ |object PM7 {
+ | List(1, 2).map({
+ | case (0| 1) => true
+ | case _ => false
+ | })
+ |}""")
+
+ @Test def testObjectWithPatternMatch8 = assertPrintedCode(sm"""
+ |object PM8 {
+ | "abcde".toList match {
+ | case Seq((car @ _), _*) => car
+ | }
+ |}""")
+
+ @Test def testObjectWithPatternMatch9 = assertPrintedCode(sm"""
+ |{
+ | object Extractor {
+ | def unapply(i: Int) = Some(i)
+ | };
+ | object PM9 {
+ | 42 match {
+ | case (a @ Extractor((i @ _))) => i
+ | }
+ | };
+ | ()
+ |}""")
+
+ @Test def testObjectWithPartialFunc = assertPrintedCode(sm"""
+ |object Test {
+ | def partFuncTest[A, B](e: Either[A, B]): scala.Unit = e match {
+ | case Right(_) => ()
+ | }
+ |}""")
+
+ @Test def testObjectWithTry = assertPrintedCode(sm"""
+ |object Test {
+ | import java.io;
+ | var file: PrintStream = null;
+ | try {
+ | val out = new FileOutputStream("myfile.txt");
+ | file = new PrintStream(out)
+ | } catch {
+ | case (ioe @ ((_): IOException)) => println("ioe")
+ | case (e @ ((_): Exception)) => println("e")
+ | } finally println("finally")
+ |}""")
+}
+
+trait TraitPrintTests {
+ @Test def testTrait = assertPrintedCode("trait *")
+
+ @Test def testTraitWithBody = assertPrintedCode(sm"""
+ |trait X {
+ | def y = "test"
+ |}""")
+
+ @Test def testTraitWithSelfTypeAndBody = assertPrintedCode(sm"""
+ |trait X { self: Order =>
+ | def y = "test"
+ |}""")
+
+ @Test def testTraitWithSelf1 = assertPrintedCode(sm"""
+ |trait X { self =>
+ | def y = "test"
+ |}""")
+
+ @Test def testTraitWithSelf2 = assertPrintedCode(sm"""
+ |trait X { self: Foo with Bar =>
+ | val x: Int = 1
+ |}""")
+
+ @Test def testTraitTypeParams = assertPrintedCode("trait X[A, B]")
+
+ @Test def testTraitWithBody2 = assertPrintedCode(sm"""
+ |trait X {
+ | def foo: scala.Unit;
+ | val bar: Baz
+ |}""")
+
+ @Test def testTraitWithInh = assertPrintedCode("trait X extends A with B")
+
+ @Test def testTraitWithEarly1 = assertPrintedCode(sm"""
+ |trait X extends {
+ | val x: Int = 1
+ |} with Any""")
+
+ @Test def testTraitWithEarly2 = assertPrintedCode(sm"""
+ |trait X extends {
+ | val x: Int = 0;
+ | type Foo = Bar
+ |} with Y""")
+
+ @Test def testTraitWithEarly3 = assertPrintedCode(sm"""
+ |trait X extends {
+ | val x: Int = 5;
+ | val y: Double = 4.0;
+ | type Foo;
+ | type XString = String
+ |} with Y""")
+
+ @Test def testTraitWithEarly4 = assertPrintedCode(sm"""
+ |trait X extends {
+ | val x: Int = 5;
+ | val y: Double = 4.0;
+ | type Foo;
+ | type XString = String
+ |} with Y {
+ | val z = 7
+ |}""")
+
+ @Test def testTraitWithEarly5 = assertPrintedCode(sm"""
+ |trait X extends {
+ | override protected[this] val x: Int = 5;
+ | val y: Double = 4.0;
+ | private type Foo;
+ | private[ee] type XString = String
+ |} with Y {
+ | val z = 7
+ |}""")
+
+ @Test def testTraitWithSingletonTypeTree = assertPrintedCode(sm"""
+ |trait Test {
+ | def testReturnSingleton(): this.type
+ |}""")
+
+ @Test def testTraitWithThis = assertPrintedCode(sm"""
+ |trait Test { _ : X with Y =>
+ |
+ |}""", q"trait Test { this: X with Y => }")
+
+ @Test def testTraitWithWhile1 = assertPrintedCode(sm"""
+ |trait Test {
+ | while (true.!=(false))
+ | println("testing...")
+ |
+ |}""")
+
+ @Test def testTraitWithWhile2 = assertPrintedCode(sm"""
+ |trait Test {
+ | while (true)
+ | {
+ | println("testing...");
+ | println("testing...")
+ | }
+ |
+ |}""")
+
+ @Test def testTraitWithDoWhile1 = assertPrintedCode(sm"""
+ |trait Test {
+ | do
+ | println("testing...")
+ | while (true)
+ |}""")
+
+ @Test def testTraitWithTypes = assertPrintedCode(sm"""
+ |trait Test {
+ | type A = Int;
+ | type B >: Nothing <: AnyRef;
+ | protected type C >: Nothing;
+ | type D <: AnyRef
+ |}""")
+}
+
+trait ValAndDefPrintTests {
+ @Test def testVal1 = assertPrintedCode("val a: Unit = null")
+
+ @Test def testVal2 = assertPrintedCode("val * : Unit = null")
+
+ @Test def testVal3 = assertPrintedCode("val a_ : Unit = null")
+
+ @Test def testDef1 = assertPrintedCode("def a: Unit = null")
+
+ @Test def testDef2 = assertPrintedCode("def * : Unit = null")
+
+ @Test def testDef3 = assertPrintedCode("def a_(x: Int): Unit = null")
+
+ @Test def testDef4 = assertPrintedCode("def a_ : Unit = null")
+
+ @Test def testDef5 = assertPrintedCode("def a_(* : Int): Unit = null")
+
+ @Test def testDef6 = assertPrintedCode("def a_(b_ : Int): Unit = null")
+
+ @Test def testDef7 = assertPrintedCode(sm"""
+ |{
+ | def test1 = ();
+ | def test2() = ()
+ |}""",
+ Block(
+ DefDef(NoMods, newTermName("test1"), Nil, Nil, EmptyTree, Literal(Constant(()))),
+ DefDef(NoMods, newTermName("test2"), Nil, Nil :: Nil, EmptyTree, Literal(Constant(())))
+ )
+ )
+
+ @Test def testDef8 = {
+ val arg = ValDef(Modifiers(Flag.IMPLICIT) , newTermName("a"),
+ AppliedTypeTree(Ident(newTypeName("R")), List(Ident(newTypeName("X")))), EmptyTree)
+
+ //def m[X](implicit a: R[X]) = ()
+ val tree = DefDef(NoMods, newTermName("test"), TypeDef(NoMods, newTypeName("X"), Nil, EmptyTree) :: Nil,
+ List(List(arg)), EmptyTree, Literal(Constant(())))
+
+ assertPrintedCode("def test[X](implicit a: R[X]) = ()", tree)
+ }
+
+ @Test def testDefWithParams1 = assertPrintedCode("def foo(x: Int*) = null")
+
+ @Test def testDefWithParams2 = assertPrintedCode("def foo(x: Int)(y: Int = 1) = null")
+
+ @Test def testDefWithTypeParams1 = assertPrintedCode("def foo[A, B, C](x: A)(y: Int = 1): C = null")
+
+ @Test def testDefWithTypeParams2 = assertPrintedCode("def foo[A, B <: Bar] = null")
+
+ @Test def testDefWithAnn1 = assertPrintedCode("@annot def foo = null")
+
+ @Test def testDefWithAnn2 = assertPrintedCode("@a(x) def foo = null")
+
+ @Test def testDefWithAnn3 = assertPrintedCode("@Foo[A, B] def foo = null")
+
+ @Test def testDefWithAnn4 = assertPrintedCode("@Foo(a)(b)(x, y) def foo = null")
+
+ @Test def testDefWithAnn5 = assertPrintedCode("@Foo[A, B](a)(b) @Bar def foo(x: Int) = null")
+
+ @Test def testDefWithAnn6 = assertPrintedCode("@test1(new test2()) def foo = 42")
+
+ @Test def testDefWithAnn7 = assertPrintedCode("@`t*` def foo = 42")
+
+ @Test def testDefWithAnn8 = assertPrintedCode("@throws(classOf[Exception]) def foo = throw new Exception()")
+
+ @Test def testAnnotated1 = assertPrintedCode("def foo = 42: @test1")
+
+ @Test def testAnnotated2 = assertPrintedCode("""def foo = 42: @test1(42, z = "5")""")
+
+ @Test def testAnnotated3 = assertPrintedCode("def foo = (42: @test1): @test2(new test1())")
+
+ @Test def testAnnotated4 = assertPrintedCode("""def foo = 42: @test1(4, "testing")(4.2)""")
+
+ @Test def testAnnotated5 = assertPrintedCode("""def foo = (42: @test1(4, "testing")(4.2)): @test2(1, "bar")(3.14)""")
+
+ @Test def testAnnotated6 = assertPrintedCode("def foo = ((42: @test1): @test2(new test1())): @test3(1)(2, 3)(4)")
+
+ @Test def testAnnotated7 = assertPrintedCode(sm"""
+ |(x: @unchecked) match {
+ | case ((_): Int) => true
+ | case _ => false
+ |}""")
+
+ @Test def testAnnotated8 = assertPrintedCode(sm"""
+ |((x: @unchecked): @test1(1, "testing")(3.14)) match {
+ | case _ => true
+ |}""")
+}
+
+trait PackagePrintTests {
+ @Test def testPackage1 = assertPrintedCode(sm"""
+ |package foo.bar {
+ |
+ |}""")
+
+ @Test def testPackage2 = assertPrintedCode(sm"""
+ |package foo {
+ | class C
+ |
+ | object D
+ |}""")
+
+ //package object foo extends a with b
+ @Test def testPackage3 = assertPrintedCode(sm"""
+ |package foo {
+ | object `package` extends a with b
+ |}""")
+
+ //package object foo { def foo; val x = 1 }
+ @Test def testPackage4 = assertPrintedCode(sm"""
+ |package foo {
+ | object `package` {
+ | def foo: scala.Unit;
+ | val x = 1
+ | }
+ |}""")
+
+ //package object foo extends { val x = 1; type I = Int } with Any
+ @Test def testPackage5 = assertPrintedCode(sm"""
+ |package foo {
+ | object `package` extends {
+ | val x = 1;
+ | type I = Int
+ | } with Any
+ |}""")
+}
+
+trait QuasiTreesPrintTests {
+ @Test def testQuasiIdent = assertPrintedCode("*", q"*")
+
+ @Test def testQuasiVal = assertPrintedCode("val * : Unit = null", q"val * : Unit = null")
+
+ @Test def testQuasiDef = assertPrintedCode("def * : Unit = null", q"def * : Unit = null")
+
+ @Test def testQuasiTrait = assertPrintedCode("trait *", q"trait *")
+
+ @Test def testQuasiClass = assertPrintedCode("class *", q"class *")
+
+ @Test def testQuasiClassWithPublicParams = assertPrintedCode( "class X(val x: Int, val s: String)", q"class X(val x: Int, val s:String)" )
+
+ @Test def testQuasiClassWithParams = assertPrintedCode("class X(x: Int, s: String)", q"class X(x: Int, s:String)")
+
+ @Test def testQuasiObject = assertPrintedCode("object *", q"object *")
+
+ @Test def testQuasiObjectWithBody = assertPrintedCode(sm"""
+ |object X {
+ | def y = "test"
+ |}""", q"""object X{ def y = "test" }""")
+
+ @Test def testQuasiClassWithBody = assertPrintedCode(sm"""
+ |class X {
+ | def y = "test"
+ |}""", q"""class X{ def y = "test" }""")
+
+ @Test def testQuasiTraitWithBody = assertPrintedCode(sm"""
+ |trait X {
+ | def y = "test"
+ |}""", q"""trait X{ def y = "test" }""")
+
+ @Test def testQuasiTraitWithSelfTypeAndBody = assertPrintedCode(sm"""
+ |trait X { self: Order =>
+ | def y = "test"
+ |}""", q"""trait X{ self: Order => def y = "test" }""")
+
+ @Test def testQuasiTraitWithSelf = assertPrintedCode(sm"""
+ |trait X { self =>
+ | def y = "test"
+ |}""", q"""trait X{ self => def y = "test" }""")
+
+ @Test def testQuasiCaseClassWithBody = assertPrintedCode(sm"""
+ |case class X() {
+ | def y = "test"
+ |}""", q"""case class X() { def y = "test" }""")
+
+ @Test def testQuasiCaseClassWithParamsAndBody = assertPrintedCode(sm"""
+ |case class X(x: Int, s: String) {
+ | def y = "test"
+ |}""", q"""case class X(x: Int, s: String){ def y = "test" }""")
+}