@@ -13,16 +13,21 @@ import dotty.tools.tasty.TastyFormat.{ASTsSection, PositionsSection, CommentsSec
13
13
import java .nio .file .{Files , Paths }
14
14
import dotty .tools .io .{JarArchive , Path }
15
15
import dotty .tools .tasty .TastyFormat .header
16
+ import scala .collection .immutable .BitSet
16
17
17
18
import scala .compiletime .uninitialized
18
19
import dotty .tools .tasty .TastyBuffer .Addr
20
+ import dotty .tools .dotc .core .Names .TermName
19
21
20
22
object TastyPrinter :
21
23
22
24
def showContents (bytes : Array [Byte ], noColor : Boolean ): String =
25
+ showContents(bytes, noColor, testPickler = false )
26
+
27
+ def showContents (bytes : Array [Byte ], noColor : Boolean , testPickler : Boolean = false ): String =
23
28
val printer =
24
- if noColor then new TastyPrinter (bytes)
25
- else new TastyAnsiiPrinter (bytes)
29
+ if noColor then new TastyPrinter (bytes, testPickler )
30
+ else new TastyAnsiiPrinter (bytes, testPickler )
26
31
printer.showContents()
27
32
28
33
def main (args : Array [String ]): Unit = {
@@ -62,7 +67,9 @@ object TastyPrinter:
62
67
println(line)
63
68
}
64
69
65
- class TastyPrinter (bytes : Array [Byte ]) {
70
+ class TastyPrinter (bytes : Array [Byte ], val testPickler : Boolean ) {
71
+
72
+ def this (bytes : Array [Byte ]) = this (bytes, testPickler = false )
66
73
67
74
class TastyPrinterUnpickler extends TastyUnpickler (bytes) {
68
75
var namesStart : Addr = uninitialized
@@ -77,39 +84,53 @@ class TastyPrinter(bytes: Array[Byte]) {
77
84
private val unpickler : TastyPrinterUnpickler = new TastyPrinterUnpickler
78
85
import unpickler .{nameAtRef , unpickle }
79
86
80
- private def nameToString (name : Name ): String = name.debugString
81
-
82
- private def nameRefToString (ref : NameRef ): String = nameToString(nameAtRef(ref))
83
-
84
87
private def printHeader (sb : StringBuilder ): Unit =
85
88
val header = unpickler.header
86
89
sb.append(" Header:\n " )
87
- sb.append(s " version: ${header.majorVersion}. ${header.minorVersion}. ${header.experimentalVersion}\n " )
88
- sb.append(" tooling: " ).append(header.toolingVersion).append(" \n " )
89
- sb.append(" UUID: " ).append(header.uuid).append(" \n " )
90
- sb.append(" \n " )
90
+ if testPickler then
91
+ // these fields are not stable when the TASTy/compiler versions change, so not useful for testing
92
+ sb.append(" version: <elided>\n " )
93
+ sb.append(" tooling: <elided>\n " )
94
+ sb.append(" UUID: <elided>\n " )
95
+ else
96
+ sb.append(s " version: ${header.majorVersion}. ${header.minorVersion}. ${header.experimentalVersion}\n " )
97
+ sb.append(" tooling: " ).append(header.toolingVersion).append(" \n " )
98
+ sb.append(" UUID: " ).append(header.uuid).append(" \n " )
99
+ end if
91
100
92
- private def printNames (sb : StringBuilder ): Unit =
93
- sb.append(s " Names ( ${unpickler.namesEnd.index - unpickler.namesStart.index} bytes, starting from ${unpickler.namesStart.index}): \n " )
101
+ private def printNames (sb : StringBuilder )(using refs : NameRefs ): Unit =
102
+ sb.append(sectionHeader(
103
+ name = " Names" ,
104
+ count = (unpickler.namesEnd.index - unpickler.namesStart.index).toString,
105
+ base = showBase(unpickler.namesStart.index),
106
+ lineEnd = true
107
+ ))
94
108
for ((name, idx) <- nameAtRef.contents.zipWithIndex) {
95
109
val index = nameStr(" %6d" .format(idx))
96
- sb.append(index).append(" : " ).append(nameToString(name )).append(" \n " )
110
+ sb.append(index).append(" : " ).append(refs.nameRefToString( NameRef (idx) )).append(" \n " )
97
111
}
98
112
99
113
def showContents (): String = {
100
114
val sb : StringBuilder = new StringBuilder
115
+ given NameRefs = unpickle0(new SourceFileUnpickler )(using NameRefs .empty).getOrElse(NameRefs .empty)
101
116
printHeader(sb)
102
117
printNames(sb)
103
- unpickle (new TreeSectionUnpickler (sb))
104
- unpickle (new PositionSectionUnpickler (sb))
105
- unpickle (new CommentSectionUnpickler (sb))
106
- unpickle (new AttributesSectionUnpickler (sb))
118
+ unpickle0 (new TreeSectionUnpickler (sb))
119
+ unpickle0 (new PositionSectionUnpickler (sb))
120
+ unpickle0 (new CommentSectionUnpickler (sb))
121
+ unpickle0 (new AttributesSectionUnpickler (sb))
107
122
sb.result
108
123
}
109
124
110
- class TreeSectionUnpickler (sb : StringBuilder ) extends SectionUnpickler [Unit ](ASTsSection ) {
125
+ def unpickle0 [R ](sec : PrinterSectionUnpickler [R ])(using NameRefs ): Option [R ] =
126
+ unpickle(new SectionUnpickler [R ](sec.name) {
127
+ def unpickle (reader : TastyReader , nameAtRef : NameTable ): R =
128
+ sec.unpickle0(reader.subReader(reader.startAddr, reader.endAddr)) // fork so we can visit multiple times
129
+ })
130
+
131
+ class TreeSectionUnpickler (sb : StringBuilder ) extends PrinterSectionUnpickler [Unit ](ASTsSection ) {
111
132
import dotty .tools .tasty .TastyFormat .*
112
- def unpickle (reader : TastyReader , tastyName : NameTable ): Unit = {
133
+ def unpickle0 (reader : TastyReader )( using refs : NameRefs ): Unit = {
113
134
import reader .*
114
135
var indent = 0
115
136
def newLine () = {
@@ -119,7 +140,7 @@ class TastyPrinter(bytes: Array[Byte]) {
119
140
def printNat () = sb.append(treeStr(" " + readNat()))
120
141
def printName () = {
121
142
val idx = readNat()
122
- sb.append(nameStr(" " + idx + " [" + nameRefToString(NameRef (idx)) + " ]" ))
143
+ sb.append(nameStr(" " + idx + " [" + refs. nameRefToString(NameRef (idx)) + " ]" ))
123
144
}
124
145
def printTree (): Unit = {
125
146
newLine()
@@ -170,19 +191,20 @@ class TastyPrinter(bytes: Array[Byte]) {
170
191
}
171
192
indent -= 2
172
193
}
173
- sb.append(s " \n\n Trees ( ${endAddr.index - startAddr.index} bytes, starting from $base ): " )
194
+ sb.append(sectionHeader( " Trees " , reader, lineEnd = false ) )
174
195
while (! isAtEnd) {
175
196
printTree()
176
197
newLine()
177
198
}
199
+ sb.append(" \n " )
178
200
}
179
201
}
180
202
181
- class PositionSectionUnpickler (sb : StringBuilder ) extends SectionUnpickler [Unit ](PositionsSection ) {
182
- def unpickle (reader : TastyReader , tastyName : NameTable ): Unit = {
203
+ class PositionSectionUnpickler (sb : StringBuilder ) extends PrinterSectionUnpickler [Unit ](PositionsSection ) {
204
+ def unpickle0 (reader : TastyReader )( using tastyName : NameRefs ): Unit = {
183
205
import reader .*
184
206
val posUnpickler = new PositionUnpickler (reader, tastyName)
185
- sb.append(s " \n\n Positions ( ${reader.endAddr.index - reader.startAddr.index} bytes, starting from $base ): \n " )
207
+ sb.append(sectionHeader( " Positions " , reader) )
186
208
val lineSizes = posUnpickler.lineSizes
187
209
sb.append(s " lines: ${lineSizes.length}\n " )
188
210
sb.append(s " line sizes: \n " )
@@ -210,12 +232,12 @@ class TastyPrinter(bytes: Array[Byte]) {
210
232
}
211
233
}
212
234
213
- class CommentSectionUnpickler (sb : StringBuilder ) extends SectionUnpickler [Unit ](CommentsSection ) {
214
- def unpickle (reader : TastyReader , tastyName : NameTable ): Unit = {
235
+ class CommentSectionUnpickler (sb : StringBuilder ) extends PrinterSectionUnpickler [Unit ](CommentsSection ) {
236
+ def unpickle0 (reader : TastyReader )( using NameRefs ): Unit = {
215
237
import reader .*
216
238
val comments = new CommentUnpickler (reader).comments
217
239
if ! comments.isEmpty then
218
- sb.append(s " \n\n Comments ( ${reader.endAddr.index - reader.startAddr.index} bytes, starting from $base ): \n " )
240
+ sb.append(sectionHeader( " Comments " , reader) )
219
241
val sorted = comments.toSeq.sortBy(_._1.index)
220
242
for ((addr, cmt) <- sorted) {
221
243
sb.append(treeStr(" %6d" .format(addr.index)))
@@ -224,12 +246,14 @@ class TastyPrinter(bytes: Array[Byte]) {
224
246
}
225
247
}
226
248
227
- class AttributesSectionUnpickler (sb : StringBuilder ) extends SectionUnpickler [Unit ](AttributesSection ) {
249
+ class AttributesSectionUnpickler (sb : StringBuilder ) extends PrinterSectionUnpickler [Unit ](AttributesSection ) {
228
250
import dotty .tools .tasty .TastyFormat .*
229
- def unpickle (reader : TastyReader , tastyName : NameTable ): Unit = {
251
+ def unpickle0 (reader : TastyReader )( using nameAtRef : NameRefs ): Unit = {
230
252
import reader .*
231
- sb.append(s " \n\n Attributes ( ${reader.endAddr.index - reader.startAddr.index} bytes, starting from $base ): \n " )
253
+ sb.append(sectionHeader( " Attributes " , reader) )
232
254
while ! isAtEnd do
255
+ // TODO: Should we elide attributes under testPickler? (i.e.
256
+ // if we add new attributes many check files will need to be updated)
233
257
val tag = readByte()
234
258
sb.append(" " ).append(attributeTagToString(tag))
235
259
if isBooleanAttrTag(tag) then ()
@@ -242,6 +266,50 @@ class TastyPrinter(bytes: Array[Byte]) {
242
266
}
243
267
}
244
268
269
+ class NameRefs (sourceFileRefs : Set [NameRef ]) extends (NameRef => TermName ):
270
+ private val isSourceFile = sourceFileRefs.map(_.index).to(BitSet )
271
+
272
+ def nameRefToString (ref : NameRef ): String = this (ref).debugString
273
+
274
+ def apply (ref : NameRef ): TermName =
275
+ if isSourceFile(ref.index) then NameRefs .elidedSourceFile
276
+ else nameAtRef(ref)
277
+
278
+ object NameRefs :
279
+ import dotty .tools .dotc .core .Names .termName
280
+
281
+ private val elidedSourceFile = termName(" <elided source file name>" )
282
+ val empty = NameRefs (Set .empty)
283
+
284
+
285
+ class SourceFileUnpickler extends PrinterSectionUnpickler [NameRefs ](PositionsSection ) {
286
+ def unpickle0 (reader : TastyReader )(using nameAtRef : NameRefs ): NameRefs = {
287
+ if ! testPickler then return NameRefs .empty
288
+ val buf = Set .newBuilder[NameRef ]
289
+ val posUnpickler = new PositionUnpickler (reader, nameAtRef)
290
+ val sources = posUnpickler.sourceNameRefs
291
+ for ((_, nameRef) <- sources.iterator) {
292
+ buf += nameRef
293
+ }
294
+ NameRefs (buf.result)
295
+ }
296
+ }
297
+
298
+ private final def showBase (index : Int ): String =
299
+ if testPickler then " <elided base index>" else index.toString()
300
+
301
+ private final def sectionHeader (name : String , reader : TastyReader , lineEnd : Boolean = true ): String =
302
+ val count = reader.endAddr.index - reader.startAddr.index
303
+ sectionHeader(name, count.toString, {showBase(reader.base)}, lineEnd)
304
+
305
+ private final def sectionHeader (name : String , count : String , base : String , lineEnd : Boolean ): String =
306
+ val suffix = if lineEnd then " \n " else " "
307
+ s " \n $name ( $count bytes, starting from $base): $suffix"
308
+
309
+ abstract class PrinterSectionUnpickler [T ](val name : String ) {
310
+ def unpickle0 (reader : TastyReader )(using refs : NameRefs ): T
311
+ }
312
+
245
313
protected def nameStr (str : String ): String = str
246
314
protected def treeStr (str : String ): String = str
247
315
protected def lengthStr (str : String ): String = str
0 commit comments