summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorVladimirNik <vladimir.nikolaev9@gmail.com>2014-02-07 02:41:54 +0400
committerVladimirNik <vladimir.nikolaev9@gmail.com>2014-02-20 01:23:25 +0400
commit931edcc94ebd73b420b2359d989442bf700588eb (patch)
tree40d1c09c1d6b32ad54d704550028eaea8873c477 /src/reflect
parent3973f29cec9f06724941b68577908f546341c45e (diff)
downloadscala-931edcc94ebd73b420b2359d989442bf700588eb.tar.gz
scala-931edcc94ebd73b420b2359d989442bf700588eb.tar.bz2
scala-931edcc94ebd73b420b2359d989442bf700588eb.zip
Attributed val/var processing for syntactics (SI-8180)
TypedTreesPrinter added changes based on pull request comments: print root packages flag; tests for syntactics; SyntacticEmptyTypeTree added to Printers
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/api/Printers.scala14
-rw-r--r--src/reflect/scala/reflect/internal/Printers.scala162
-rw-r--r--src/reflect/scala/reflect/internal/ReificationSupport.scala58
3 files changed, 201 insertions, 33 deletions
diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala
index b262fdce68..3591712708 100644
--- a/src/reflect/scala/reflect/api/Printers.scala
+++ b/src/reflect/scala/reflect/api/Printers.scala
@@ -209,21 +209,23 @@ trait Printers { self: Universe =>
* 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.
+ * #1 is available for unattributed trees and attributed trees
* #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.
+ * left in place, and that's what we plan to improve in the future.
+ * printTypes, printIds, printPositions options have the same meaning as for TreePrinter
+ * printRootPkg option is available only for attributed trees.
*
* @group Printers
*/
- def showCode(tree: Tree) = render(tree, newCodePrinter)
+ def showCode(tree: Tree, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printPositions: BooleanFlag = None, printRootPkg: Boolean = false) =
+ render(tree, newCodePrinter(_, tree, printRootPkg), printTypes, printIds, None, None, printPositions)
/**
* Hook to define what `showCode(...)` means.
* @group Printers
*/
- protected def newCodePrinter(out: PrintWriter): TreePrinter
-
+ protected def newCodePrinter(out: PrintWriter, tree: Tree, printRootPkg: Boolean): 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 b1d76b6056..cb4abd8bd8 100644
--- a/src/reflect/scala/reflect/internal/Printers.scala
+++ b/src/reflect/scala/reflect/internal/Printers.scala
@@ -74,6 +74,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
def undent() = indentMargin -= indentStep
def printPosition(tree: Tree) = if (printPositions) print(tree.pos.show)
+
+ protected def printTypesInfo(tree: Tree) =
+ if (printTypes && tree.isTerm && tree.canHaveAttrs)
+ print("{", if (tree.tpe eq null) "<null>" else tree.tpe.toString, "}")
def println() = {
out.println()
@@ -279,9 +283,9 @@ trait Printers extends api.Printers { self: SymbolTable =>
if (printOwners && tree.symbol != null) print("@" + tree.symbol.owner.id)
}
- protected def printSuper(tree: Super, resultName: => String) = {
+ protected def printSuper(tree: Super, resultName: => String, checkSymbol: Boolean = true) = {
val Super(This(qual), mix) = tree
- if (qual.nonEmpty || tree.symbol != NoSymbol) print(resultName + ".")
+ if (qual.nonEmpty || (checkSymbol && tree.symbol != NoSymbol)) print(resultName + ".")
print("super")
if (mix.nonEmpty) print(s"[$mix]")
}
@@ -498,9 +502,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
case tree =>
xprintTree(this, tree)
}
- if (printTypes && tree.isTerm && tree.canHaveAttrs) {
- print("{", if (tree.tpe eq null) "<null>" else tree.tpe.toString, "}")
- }
+ printTypesInfo(tree)
}
def print(args: Any*): Unit = args foreach {
@@ -516,19 +518,6 @@ trait Printers extends api.Printers { self: SymbolTable =>
// 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
@@ -582,7 +571,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
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)
+ case _ => render(t, new ParsedTreePrinter(_))
}
}
@@ -635,6 +624,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
def printParam(tree: Tree, primaryCtorParam: Boolean): Unit =
tree match {
case vd @ ValDef(mods, name, tp, rhs) =>
+ printPosition(tree)
printAnnotations(vd)
val mutableOrOverride = mods.isOverride || mods.isMutable
val hideCtorMods = mods.isParamAccessor && mods.isPrivateLocal && !mutableOrOverride
@@ -648,6 +638,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
printOpt(": ", tp);
printOpt(" = ", rhs)
case TypeDef(_, name, tparams, rhs) =>
+ printPosition(tree)
print(printedName(name))
printTypeParams(tparams);
print(rhs)
@@ -682,6 +673,13 @@ trait Printers extends api.Printers { self: SymbolTable =>
override def printTree(tree: Tree): Unit = {
parentsStack.push(tree)
+ try {
+ processTreePrinting(tree);
+ printTypesInfo(tree)
+ } finally parentsStack.pop()
+ }
+
+ def processTreePrinting(tree: Tree): Unit = {
tree match {
case cl @ ClassDef(mods, name, tparams, impl) =>
if (mods.isJavaDefined) super.printTree(cl)
@@ -733,12 +731,11 @@ trait Printers extends api.Printers { self: SymbolTable =>
printSeq(stats) {
print(_)
} {
- print(";");
+ println()
println()
};
case _ =>
- val separator = scala.util.Properties.lineSeparator
- printPackageDef(pd, separator)
+ printPackageDef(pd, scala.util.Properties.lineSeparator)
}
case md @ ModuleDef(mods, name, impl) =>
@@ -786,7 +783,8 @@ trait Printers extends api.Printers { self: SymbolTable =>
case imp @ Import(expr, _) =>
printImport(imp, resolveSelect(expr))
- case Template(parents, self, body) =>
+ case t @ Template(parents, self, tbody) =>
+ val body = build.unattributedTemplBody(t)
val printedParents =
currentParent map {
case _: CompoundTypeTree => parents
@@ -840,7 +838,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
case dd: DefDef => dd.name != nme.CONSTRUCTOR
case _ => true
}
- val modBody = left ::: right.drop(1)
+ val modBody = (left ::: right.drop(1))
val showBody = !(modBody.isEmpty && (self == noSelfType || self.isEmpty))
if (showBody) {
if (self.name != nme.WILDCARD) {
@@ -996,15 +994,127 @@ trait Printers extends api.Printers { self: SymbolTable =>
case tree => super.printTree(tree)
}
- parentsStack.pop()
}
}
+ // it's the printer for trees after typer phases
+ class TypedTreePrinter(out: PrintWriter, printRootPkg: Boolean) extends ParsedTreePrinter(out) {
+ override def printOpt(prefix: String, tree: Tree) =
+ if (!emptyTree(tree)) super.printOpt(prefix, tree)
+
+ def syntheticToRemove(tree: Tree) =
+ tree match {
+ case _: ValDef | _: TypeDef => false // don't remove ValDef and TypeDef
+ case md: MemberDef if md.mods.isSynthetic => true
+ case _ => false
+ }
+
+ override def printColumn(ts: List[Tree], start: String, sep: String, end: String) = {
+ super.printColumn(ts.filter(!syntheticToRemove(_)), start, sep, end)
+ }
+
+ protected def emptyTree(tree: Tree) = tree match {
+ case EmptyTree | build.SyntacticEmptyTypeTree() => true
+ case _ => false
+ }
+
+ def originalTypeTrees(trees: List[Tree]) =
+ trees.filter(!emptyTree(_)) map {
+ case tt: TypeTree => tt.original
+ case tree => tree
+ }
+
+ override protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) =
+ super.removeDefaultClassesFromList(originalTypeTrees(trees), classesToRemove)
+
+ override def resolveSelect(t: Tree): String = {
+ t match {
+ case _: Select | _: Ident => super.resolveSelect(t)
+ case _ => render(t, new TypedTreePrinter(_, printRootPkg))
+ }
+ }
+
+ override def processTreePrinting(tree: Tree): Unit = {
+ tree match {
+ // don't remove synthetic ValDef/TypeDef
+ case _ if syntheticToRemove(tree) =>
+
+ case tt: TypeTree =>
+ if (printPositions) {
+ if (tt.original != null)
+ print("<type: ", tt.original.toString(), ">")
+ else print("<type ?>")
+ } else if (!emptyTree(tt)) print(tt.original)
+
+ // print only fun when targs are TypeTrees with empty original
+ case TypeApply(fun, targs) =>
+ if (targs.exists(emptyTree(_))) {
+ print(fun)
+ } else super.processTreePrinting(tree)
+
+ case UnApply(fun, args) =>
+ fun match {
+ case treeInfo.Unapplied(body) =>
+ body match {
+ case Select(qual, name) if name == nme.unapply => print(qual)
+ case TypeApply(Select(qual, name), args) if name == nme.unapply || name == nme.unapplySeq =>
+ print(TypeApply(qual, args))
+ case _ => print(body)
+ }
+ case _ => print(fun)
+ }
+ printRow(args, "(", ", ", ")")
+
+ // remove this.this from constructor invocation
+ case Select(This(_), name @ nme.CONSTRUCTOR) => print(printedName(name))
+
+ case Select(qual, name) =>
+ def checkRootPackage(tr: Tree): Boolean =
+ (currentParent match { //check that Select is not for package def name
+ case Some(_: PackageDef) => false
+ case _ => true
+ }) && (tr match { // check that Select contains package
+ case Select(q, _) => checkRootPackage(q)
+ case _: Ident | _: This => val sym = tr.symbol
+ tr.hasExistingSymbol && sym.isPackage && !sym.isRootPackage
+ case _ => false
+ })
+
+ if (printRootPkg && checkRootPackage(tree)) print(s"${printedName(nme.ROOTPKG)}.")
+ super.processTreePrinting(tree)
+
+ case Typed(expr, tp) =>
+ def printTp = print("(", tp, ")")
+
+ tp match {
+ case EmptyTree | build.SyntacticEmptyTypeTree() | _: Annotated => printTp
+ case tt: TypeTree if tt.original.isInstanceOf[Annotated] => printTp
+ case _ => super.processTreePrinting(tree)
+ }
+
+ case This(qual) =>
+ if (tree.symbol.isPackage) print(tree.symbol.fullName)
+ else super.processTreePrinting(tree)
+
+ case st @ Super(th @ This(qual), mix) =>
+ printSuper(st, printedName(qual), checkSymbol = false)
+
+ case tree => super.processTreePrinting(tree)
+ }
+ }
+ }
+
/** 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 newCodePrinter(writer: PrintWriter, tree: Tree, printRootPkg: Boolean): TreePrinter = {
+ if (build.detectAttributedTree(tree))
+ new TypedTreePrinter(writer, printRootPkg)
+ else
+ 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/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala
index 087d4186be..44cda24242 100644
--- a/src/reflect/scala/reflect/internal/ReificationSupport.scala
+++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala
@@ -234,10 +234,66 @@ trait ReificationSupport { self: SymbolTable =>
}
}
+ private[internal] def detectAttributedTree(tree: Tree) =
+ tree.hasExistingSymbol || tree.exists {
+ case dd: DefDef => dd.mods.hasAccessorFlag || dd.mods.isSynthetic // for untypechecked trees
+ case md: MemberDef => md.hasExistingSymbol
+ case _ => false
+ }
+
+ // recover template body to parsed state
+ private[internal] def unattributedTemplBody(templ: Template) = {
+ val tbody = templ.body
+
+ def filterBody(body: List[Tree]) = body filter {
+ case _: ValDef | _: TypeDef => true
+ // keep valdef or getter for val/var
+ case dd: DefDef if dd.mods.hasAccessorFlag => !nme.isSetterName(dd.name) && !tbody.exists{
+ case vd: ValDef => dd.name == vd.name.dropLocal
+ case _ => false
+ }
+ case md: MemberDef => !md.mods.isSynthetic
+ case tree => true
+ }
+
+ def lazyValDefRhs(body: Tree) =
+ body match {
+ case Block(List(Assign(_, rhs)), _) => rhs
+ case _ => body
+ }
+
+ def recoverBody(body: List[Tree]) = body map {
+ case vd @ ValDef(vmods, vname, _, vrhs) if nme.isLocalName(vname) =>
+ tbody find {
+ case dd: DefDef => dd.name == vname.dropLocal
+ case _ => false
+ } map { dd =>
+ val DefDef(dmods, dname, _, _, _, drhs) = dd
+ // get access flags from DefDef
+ val vdMods = (vmods &~ Flags.AccessFlags) | (dmods & Flags.AccessFlags).flags
+ // for most cases lazy body should be taken from accessor DefDef
+ val vdRhs = if (vmods.isLazy) lazyValDefRhs(drhs) else vrhs
+ copyValDef(vd)(mods = vdMods, name = dname, rhs = vdRhs)
+ } getOrElse (vd)
+ // for abstract and some lazy val/vars
+ case dd @ DefDef(mods, name, _, _, tpt, rhs) if mods.hasAccessorFlag =>
+ // transform getter mods to field
+ val vdMods = (if (!mods.hasStableFlag) mods | Flags.MUTABLE else mods &~ Flags.STABLE) &~ Flags.ACCESSOR
+ ValDef(vdMods, name, tpt, rhs)
+ case tree => tree
+ }
+
+ if (detectAttributedTree(templ)) {
+ recoverBody(filterBody(tbody))
+ } else tbody
+ }
+
// undo gen.mkTemplate
protected object UnMkTemplate {
def unapply(templ: Template): Option[(List[Tree], ValDef, Modifiers, List[List[ValDef]], List[Tree], List[Tree])] = {
- val Template(parents, selfType, tbody) = templ
+ val Template(parents, selfType, _) = templ
+ val tbody = unattributedTemplBody(templ)
+
def result(ctorMods: Modifiers, vparamss: List[List[ValDef]], edefs: List[Tree], body: List[Tree]) =
Some((parents, selfType, ctorMods, vparamss, edefs, body))
def indexOfCtor(trees: List[Tree]) =