summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-07-03 19:14:30 +0000
committerPaul Phillips <paulp@improving.org>2009-07-03 19:14:30 +0000
commit5f06ad4179d135d579a857dfe6be096eb39e2c13 (patch)
treea8281347b303513e27cdc201e55cf250ace61df7
parent70b9c762e8b26f27f34fce76e89b4710a6fcc10b (diff)
downloadscala-5f06ad4179d135d579a857dfe6be096eb39e2c13.tar.gz
scala-5f06ad4179d135d579a857dfe6be096eb39e2c13.tar.bz2
scala-5f06ad4179d135d579a857dfe6be096eb39e2c13.zip
Wrote a subclass of tree printer which outputs ...
Wrote a subclass of tree printer which outputs more to my liking.
-rw-r--r--src/compiler/scala/tools/nsc/matching/MatchUtil.scala72
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala70
-rw-r--r--src/compiler/scala/tools/nsc/matching/TransMatcher.scala105
3 files changed, 163 insertions, 84 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/MatchUtil.scala b/src/compiler/scala/tools/nsc/matching/MatchUtil.scala
index cbbb736d2d..e6cf468328 100644
--- a/src/compiler/scala/tools/nsc/matching/MatchUtil.scala
+++ b/src/compiler/scala/tools/nsc/matching/MatchUtil.scala
@@ -13,62 +13,22 @@ object MatchUtil
def impossible: Nothing = abort("this never happens")
def abort(msg: String): Nothing = throw new RuntimeException(msg)
- object Implicits {
- implicit def listPlusOps[T](xs: List[T]) = new ListPlus(xs)
- }
-
- class ListPlus[A](list: List[A]) {
- /** Returns the list without the element at index <code>n</code>.
- * If this list has fewer than <code>n</code> elements, the same list is returned.
- *
- * @param n the index of the element to drop.
- * @return the list without the <code>n</code>th element.
- */
- def dropIndex(n: Int) = list.take(n) ::: list.drop(n + 1)
-
- /** Returns a list formed from this list and the specified lists <code>list2</code>
- * and <code>list3</code> by associating each element of the first list with
- * the elements at the same positions in the other two.
- * If any of the lists is shorter than the others, later elements in the other two are ignored.
- *
- * @return <code>List((a<sub>0</sub>,b<sub>0</sub>), ...,
- * (a<sub>min(m,n)</sub>,b<sub>min(m,n)</sub>))</code> when
- * <code>List(a<sub>0</sub>, ..., a<sub>m</sub>)
- * zip List(b<sub>0</sub>, ..., b<sub>n</sub>)</code> is invoked.
- */
- def zip3[B, C](list2: List[B], list3: List[C]): List[(A, B, C)] = {
- val b = new ListBuffer[(A, B, C)]
- var xs1 = list
- var xs2 = list2
- var xs3 = list3
- while (!xs1.isEmpty && !xs2.isEmpty && !xs3.isEmpty) {
- b += ((xs1.head, xs2.head, xs3.head))
- xs1 = xs1.tail
- xs2 = xs2.tail
- xs3 = xs3.tail
- }
- b.toList
- }
- }
-
- object ListPlus {
- /** Transforms a list of triples into a triple of lists.
- *
- * @param xs the list of triples to unzip
- * @return a triple of lists.
- */
- def unzip3[A,B,C](xs: List[(A,B,C)]): (List[A], List[B], List[C]) = {
- val b1 = new ListBuffer[A]
- val b2 = new ListBuffer[B]
- val b3 = new ListBuffer[C]
- var xc = xs
- while (!xc.isEmpty) {
- b1 += xc.head._1
- b2 += xc.head._2
- b3 += xc.head._3
- xc = xc.tail
- }
- (b1.toList, b2.toList, b3.toList)
+ /** Transforms a list of triples into a triple of lists.
+ *
+ * @param xs the list of triples to unzip
+ * @return a triple of lists.
+ */
+ def unzip3[A,B,C](xs: List[(A,B,C)]): (List[A], List[B], List[C]) = {
+ val b1 = new ListBuffer[A]
+ val b2 = new ListBuffer[B]
+ val b3 = new ListBuffer[C]
+ var xc = xs
+ while (!xc.isEmpty) {
+ b1 += xc.head._1
+ b2 += xc.head._2
+ b3 += xc.head._3
+ xc = xc.tail
}
+ (b1.toList, b2.toList, b3.toList)
}
}
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index 353b8c4102..44fe1456fa 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -11,8 +11,6 @@ import util.Position
import collection._
import mutable.BitSet
import immutable.IntMap
-import MatchUtil.ListPlus._
-import MatchUtil.Implicits._
import MatchUtil._
/** Translation of match expressions.
@@ -49,7 +47,7 @@ trait ParallelMatching extends ast.TreeDSL {
def ifDebug(body: => Unit): Unit = { if (settings.debug.value) body }
def DBG(msg: String): Unit = { ifDebug(println(msg)) }
- def TRACE(f: String, xs: String*): Unit = { if (trace) println(f.format(xs : _*)) }
+ def TRACE(f: String, xs: Any*): Unit = { if (trace) println(if (xs.isEmpty) f else f.format(xs : _*)) }
def logAndReturn[T](s: String, x: T): T = { log(s + x.toString) ; x }
def traceAndReturn[T](s: String, x: T): T = { TRACE(s + x.toString) ; x }
@@ -808,7 +806,7 @@ trait ParallelMatching extends ast.TreeDSL {
( for ((i, l) <- labels) yield "labels(%d) = %s".format(i, l) ) ++
( for ((s, v) <- List("bx" -> bx, "label.tpe" -> label.tpe)) yield "%s = %s".format(s, v) )
- xs.flatten mkString "\n"
+ xs mkString "\n"
}
// sanity checks: same length lists and args are conformant with formals
def isConsistent() = (fmls.length == args.length) && List.forall2(args, fmls)(_.tpe <:< _)
@@ -917,6 +915,21 @@ trait ParallelMatching extends ast.TreeDSL {
if (row.length != row1.length) make(temp, row) // recursive call if any change
else Rep(temp, row).init
}
+
+ override def toString() = {
+ val toPrint: List[(Any, Traversable[Any])] =
+ ((vss.zipWithIndex map (_.swap)) :::
+ List[(Any, Traversable[Any])](
+ "labels" -> labels,
+ "targets" -> targets,
+ "reached" -> reached,
+ "shortCuts" -> shortCuts)
+ ) filterNot (_._2.isEmpty)
+ val strs = toPrint map { case (k, v) => " %s = %s\n".format(k, v) }
+
+ if (toPrint.isEmpty) "RepFactory()"
+ else "RepFactory(\n%s)".format(strs mkString)
+ }
}
case class Combo(index: Int, sym: Symbol)
@@ -976,30 +989,33 @@ trait ParallelMatching extends ast.TreeDSL {
*
* tmp1 tmp_m
*/
- final def applyRule(implicit theOwner: Symbol, rep: RepFactory): RuleApplication = row match {
- case Nil => ErrorRule()
- case Row(pats, subst, g, bx) :: xs =>
-
- var bnd = subst
- for (((rpat, t), px) <- pats zip temp zipWithIndex) {
- val Strip(vs, p) = rpat
-
- if (isDefaultPattern(p)) bnd = bnd.add(vs, t)
- else {
- // Row( _ ... _ p_1i ... p_1n g_m b_m ) :: rows
- // cut out column px that contains the non-default pattern
- val column = rpat :: (row.tail map (_ pat px))
- val restTemp = temp dropIndex px
- val restRows = row map (r => r replace (r.pat dropIndex px))
- val mr = MixtureRule(new Scrutinee(t), column, rep.make(restTemp, restRows))
-
- // TRACE("Mixture rule is = " + mr.getClass)
- return mr
+ final def applyRule(implicit theOwner: Symbol, rep: RepFactory): RuleApplication = {
+ def dropIndex[T](xs: List[T], n: Int) = (xs take n) ::: (xs drop (n + 1))
+ row match {
+ case Nil => ErrorRule()
+ case Row(pats, subst, g, bx) :: xs =>
+
+ var bnd = subst
+ for (((rpat, t), px) <- pats zip temp zipWithIndex) {
+ val Strip(vs, p) = rpat
+
+ if (isDefaultPattern(p)) bnd = bnd.add(vs, t)
+ else {
+ // Row( _ ... _ p_1i ... p_1n g_m b_m ) :: rows
+ // cut out column px that contains the non-default pattern
+ val column = rpat :: (row.tail map (_ pat px))
+ val restTemp = dropIndex(temp, px)
+ val restRows = row map (r => r replace dropIndex(r.pat, px))
+ val mr = MixtureRule(new Scrutinee(t), column, rep.make(restTemp, restRows))
+
+ // TRACE("Mixture rule is = " + mr.getClass)
+ return mr
+ }
}
- }
- // Row( _ ... _ g_1 b_1 ) :: rows it's all default patterns
- val rest = if (g.isEmpty) null else rep.make(temp, xs) // TODO - why null?
- VariableRule (bnd, g, rest, bx)
+ // Row( _ ... _ g_1 b_1 ) :: rows it's all default patterns
+ val rest = if (g.isEmpty) null else rep.make(temp, xs) // TODO - why null?
+ VariableRule (bnd, g, rest, bx)
+ }
}
// a fancy toString method for debugging
diff --git a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
index a348ea83a4..183b54494e 100644
--- a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
+++ b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
@@ -8,12 +8,15 @@
package scala.tools.nsc.matching
import util.Position
+import ast.{ TreePrinters, Trees }
+import symtab.SymbolTable
+import java.io.{ StringWriter, PrintWriter }
/** Translation of pattern matching
*
* @author Burak Emir
*/
-trait TransMatcher extends ast.TreeDSL {
+trait TransMatcher extends ast.TreeDSL with CompactTreePrinter {
self: transform.ExplicitOuter with PatternNodes with ParallelMatching with CodeFactory =>
import global.{ typer => _, _ }
@@ -81,15 +84,28 @@ trait TransMatcher extends ast.TreeDSL {
val mch = typer typed irep.toTree
var dfatree = typer typed Block(vds, mch)
+ TRACE("handlePattern(\n tmps = %s\n cases = %s\n rep = %s\n initRep = %s\n)",
+ tmps, cases.mkString("(\n ", "\n ", "\n)"), rep, irep)
+ TRACE("dfatree(1) = " + toCompactString(dfatree))
+
// cannot use squeezedBlock because of side-effects, see t275
for ((cs, bx) <- cases.zipWithIndex)
if (!rep.isReached(bx)) cunit.error(cs.body.pos, "unreachable code")
dfatree = rep cleanup dfatree
resetTraverser traverse dfatree
+ TRACE("dfatree(2) = " + toCompactString(dfatree))
dfatree
}
+ private def toCompactString(t: Tree): String = {
+ val buffer = new StringWriter()
+ val printer = compactTreePrinters.create(new PrintWriter(buffer))
+ printer.print(t)
+ printer.flush()
+ buffer.toString
+ }
+
private object resetTraverser extends Traverser {
override def traverse(x: Tree): Unit = x match {
case vd: ValDef =>
@@ -101,3 +117,90 @@ trait TransMatcher extends ast.TreeDSL {
}
}
}
+
+/** A tree printer which is stingier about vertical whitespace and unnecessary
+ * punctuation than the standard one.
+ */
+trait CompactTreePrinter {
+ val global: Global
+
+ object compactTreePrinters extends {
+ val trees: global.type = global
+ } with TreePrinters {
+ import trees._
+
+ override def create(writer: PrintWriter): TreePrinter = new TreePrinter(writer) {
+ // drill down through Blocks and pull out the real statements.
+ def allStatements(t: Tree): List[Tree] = t match {
+ case Block(stmts, expr) => (stmts flatMap allStatements) ::: List(expr)
+ case _ => List(t)
+ }
+
+ override def printRaw(tree: Tree): Unit = {
+ // routing supercalls through this for debugging ease
+ def s() = {
+ // Console.println("toSuper: " + tree.getClass)
+ super.printRaw(tree)
+ }
+
+ tree match {
+ // labels used for jumps - does not map to valid scala code
+ case LabelDef(name, params, rhs) =>
+ print("labeldef %s(%s) = ".format(name, params mkString ","))
+ printRaw(rhs)
+
+ // target.method(arg) ==> target method arg
+ case Apply(Select(target, method), List(arg)) =>
+ (target, arg) match {
+ case (_: Ident, _: Literal | _: Ident) =>
+ printRaw(target)
+ print(" %s " format method)
+ printRaw(arg)
+ case _ => s()
+ }
+
+ // case Select(Select(_, x), y) if x.toString == "this" =>
+ // print(symName(tree, y))
+ // target.unary_! ==> !target
+ case Select(qualifier, name) =>
+ val n = symName(tree, name)
+ if (n startsWith "unary_") {
+ print(n drop 6)
+ print(qualifier)
+ }
+ else s()
+
+ // target.toString() ==> target.toString
+ case Apply(fn, Nil) => printRaw(fn)
+
+ // if a Block only continues one actual statement, just print it.
+ case Block(stats, expr) =>
+ allStatements(tree) match {
+ case List(x) => printRow(List(x), "", ";", "")
+ case _ => s()
+ }
+
+ // If thenp or elsep has only one statement, it doesn't need more than one line.
+ case If(cond, thenp, elsep) =>
+ printRow(List(cond), "if (", "", ") ")
+
+ allStatements(thenp) match {
+ case List(x) => printRow(List(x), "", ";", "")
+ case _ => printRaw(thenp)
+ }
+ println
+ allStatements(elsep) match {
+ case Nil =>
+ case List(x) => printRow(List(x), "else ", "", "")
+ case xs => print("else ") ; printRaw(elsep)
+ }
+ case _ => s()
+ }
+ }
+ // override def symName(tree: Tree, name: Name): String =
+ // super.symName(tree, name).replaceAll("""^(.*)\.""", "")
+ }
+ }
+
+ lazy val compactTreePrinter = compactTreePrinters.create()
+}