summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/util/Tracer.scala
blob: ec1eaa13eacd1775b4e1338dd1b8a07992219efd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/* NSC -- new Scala compiler
 * Copyright 2005-2011 LAMP/EPFL
 * @author  Paul Phillips
 */

package scala.tools.nsc
package util

import java.io.PrintStream
import scala.runtime.ScalaRunTime

class Tracer(enabled: () => Boolean) {
  def out: PrintStream = System.out
  def intoString(x: Any): String = "" + x

  def stringify(x: Any) = ScalaRunTime stringOf x

  // So can pass tuples, lists, whatever as arguments and don't
  // get a lot of extra parens or noisy prefixes.
  def stringifyArgs(x: Any) = {
    x match {
      case x: TraversableOnce[_] => x map stringify mkString ", "
      case x: Product            => x.productIterator map stringify mkString ", "
      case _                     => stringify(x)
    }
  }

  private val LBRACE = "{"
  private val RBRACE = "}"
  private var indentLevel = 0
  private def spaces = " " * (indentLevel * 2)
  private def pblock(result: Any) = {
    p(LBRACE + "\n")
    indented(p(spaces + stringify(result) + "\n"))
    p(spaces + RBRACE + "\n")
  }
  private def passign(name: String, args: String) =
    p(spaces + name + "(" + args + ") = ")

  private def indented[T](body: => T): T = {
    indentLevel += 1
    try body
    finally indentLevel -= 1
  }
  private def p(s: String) = {
    out.print(s)
    out.flush()
  }

  def apply[T](name: String, args: => Any)(body: => T): T = {
    val result = body

    if (enabled()) {
      passign(name, stringifyArgs(args))
      // concise output optimization
      val isOneliner = result match {
        case _: Boolean | _: None.type => true
        case s: String                 => s.length < 40
        case _                         => false
      }
      if (isOneliner) p(stringify(result) + "\n")
      else pblock(result)
    }

    result
  }
}

object Tracer {
  def apply(enabled: => Boolean): Tracer = new Tracer(() => enabled)
}