aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala
blob: ce3722ff145a1c1519a6cb7b4cd344ac85662443 (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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package dotty.tools.dotc
package core
package tasty

import Contexts._, Decorators._
import printing.Texts._
import TastyName._
import StdNames._
import TastyUnpickler._
import TastyBuffer.Addr
import util.Positions.{Position, offsetToInt}
import collection.mutable

class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) {

  val unpickler = new TastyUnpickler(bytes)
  import unpickler.{tastyName, unpickle}

  def nameToString(name: TastyName): String = name match {
    case Simple(name) => name.toString
    case Qualified(qual, name) => nameRefToString(qual) + "." + nameRefToString(name)
    case Signed(original, params, result) =>
      i"${nameRefToString(original)}@${params.map(nameRefToString)}%,%:${nameRefToString(result)}"
    case Expanded(prefix, original) => s"$prefix${nme.EXPAND_SEPARATOR}$original"
    case ModuleClass(original) => nameRefToString(original) + "/MODULECLASS"
    case SuperAccessor(accessed) => nameRefToString(accessed) + "/SUPERACCESSOR"
    case DefaultGetter(meth, num) => nameRefToString(meth) + "/DEFAULTGETTER" + num
    case Shadowed(original) => nameRefToString(original) + "/SHADOWED"
  }

  def nameRefToString(ref: NameRef): String = nameToString(tastyName(ref))

  def printNames() =
    for ((name, idx) <- tastyName.contents.zipWithIndex) {
      val index = "%4d: ".format(idx)
      println(index + nameToString(name))
    }

  def printContents(): Unit = {
    println("Names:")
    printNames()
    println("Trees:")
    unpickle(new TreeSectionUnpickler)
    unpickle(new PositionSectionUnpickler)
  }

  class TreeSectionUnpickler extends SectionUnpickler[Unit]("ASTs") {
    import TastyFormat._
    def unpickle(reader: TastyReader, tastyName: TastyName.Table): Unit = {
      import reader._
      var indent = 0
      def newLine() = {
        val length = "%5d:".format(index(currentAddr) - index(startAddr))
        print(s"\n $length" + " " * indent)
      }
      def printNat() = print(" " + readNat())
      def printName() = {
        val idx = readNat()
        print(" ") ;print(idx); print("["); print(nameRefToString(NameRef(idx))); print("]")
      }
      def printTree(): Unit = {
        newLine()
        val tag = readByte()
        print(" ");print(astTagToString(tag))
        indent += 2
        if (tag >= firstLengthTreeTag) {
          val len = readNat()
          print(s"($len)")
          val end = currentAddr + len
          def printTrees() = until(end)(printTree())
          tag match {
            case RENAMED =>
              printName(); printName()
            case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM | NAMEDARG | BIND =>
              printName(); printTrees()
            case REFINEDtype =>
              printName(); printTree(); printTrees()
            case RETURN =>
              printNat(); printTrees()
            case METHODtype | POLYtype | TYPELAMBDAtype =>
              printTree()
              until(end) { printName(); printTree() }
            case PARAMtype =>
              printNat(); printNat()
            case _ =>
              printTrees()
          }
          if (currentAddr != end) {
            println(s"incomplete read, current = $currentAddr, end = $end")
            goto(end)
          }
        }
        else if (tag >= firstNatASTTreeTag) {
          tag match {
            case IDENT | SELECT | TERMREF | TYPEREF | SELFDEF => printName()
            case _ => printNat()
          }
          printTree()
        }
        else if (tag >= firstASTTreeTag)
          printTree()
        else if (tag >= firstNatTreeTag)
          tag match {
            case TERMREFpkg | TYPEREFpkg | STRINGconst | IMPORTED => printName()
            case _ => printNat()
          }
        indent -= 2
      }
      println(i"start = ${reader.startAddr}, base = $base, current = $currentAddr, end = $endAddr")
      println(s"${endAddr.index - startAddr.index} bytes of AST, base = $currentAddr")
      while (!isAtEnd) {
        printTree()
        newLine()
      }
    }
  }

  class PositionSectionUnpickler extends SectionUnpickler[Unit]("Positions") {
    def unpickle(reader: TastyReader, tastyName: TastyName.Table): Unit = {
      print(s"${reader.endAddr.index - reader.currentAddr.index}")
      val positions = new PositionUnpickler(reader).positions
      println(s" position bytes:")
      val sorted = positions.toSeq.sortBy(_._1.index)
      for ((addr, pos) <- sorted) println(s"${addr.index}: ${offsetToInt(pos.start)} .. ${pos.end}")
    }
  }
}