diff --git a/compiler/src/dotty/tools/dotc/core/tasty/AttributePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/AttributePickler.scala new file mode 100644 index 000000000000..e948d8bb5fef --- /dev/null +++ b/compiler/src/dotty/tools/dotc/core/tasty/AttributePickler.scala @@ -0,0 +1,25 @@ +package dotty.tools.dotc.core.tasty + +import dotty.tools.dotc.ast.{tpd, untpd} + +import dotty.tools.tasty.TastyBuffer +import dotty.tools.tasty.TastyFormat.AttributesSection + +import java.nio.charset.StandardCharsets + +object AttributePickler: + + def pickleAttributes( + attributes: List[String], + pickler: TastyPickler, + buf: TastyBuffer): Unit = + if attributes != Nil then + pickler.newSection(AttributesSection, buf) + for attribute <- attributes do + val bytes = attribute.getBytes(StandardCharsets.UTF_8).nn + val length = bytes.length + buf.writeNat(length) + buf.writeBytes(bytes, length) + end pickleAttributes + +end AttributePickler diff --git a/compiler/src/dotty/tools/dotc/core/tasty/AttributeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/AttributeUnpickler.scala new file mode 100644 index 000000000000..5c9b89bf3b0a --- /dev/null +++ b/compiler/src/dotty/tools/dotc/core/tasty/AttributeUnpickler.scala @@ -0,0 +1,26 @@ +package dotty.tools.dotc +package core.tasty + +import scala.language.unsafeNulls + +import dotty.tools.tasty.{TastyReader, TastyBuffer} + +import java.nio.charset.StandardCharsets + +class AttributeUnpickler(reader: TastyReader): + import reader._ + + private[tasty] lazy val attributes: List[String] = { + val attributesBuilder = List.newBuilder[String] + while (!isAtEnd) { + val length = readNat() + if (length > 0) { + val bytes = readBytes(length) + val attribute = new String(bytes, StandardCharsets.UTF_8) + attributesBuilder += attribute + } + } + attributesBuilder.result() + } + +end AttributeUnpickler diff --git a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala index b35c5c9f1acc..f5cb66c0decf 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala @@ -13,17 +13,17 @@ import Names.SimpleName import TreeUnpickler.UnpickleMode import dotty.tools.tasty.TastyReader -import dotty.tools.tasty.TastyFormat.{ASTsSection, PositionsSection, CommentsSection} +import dotty.tools.tasty.TastyFormat.{ASTsSection, PositionsSection, CommentsSection, AttributesSection} object DottyUnpickler { /** Exception thrown if classfile is corrupted */ class BadSignature(msg: String) extends RuntimeException(msg) - class TreeSectionUnpickler(posUnpickler: Option[PositionUnpickler], commentUnpickler: Option[CommentUnpickler]) + class TreeSectionUnpickler(posUnpickler: Option[PositionUnpickler], commentUnpickler: Option[CommentUnpickler], attributeUnpickler: Option[AttributeUnpickler]) extends SectionUnpickler[TreeUnpickler](ASTsSection) { def unpickle(reader: TastyReader, nameAtRef: NameTable): TreeUnpickler = - new TreeUnpickler(reader, nameAtRef, posUnpickler, commentUnpickler) + new TreeUnpickler(reader, nameAtRef, posUnpickler, commentUnpickler, attributeUnpickler) } class PositionsSectionUnpickler extends SectionUnpickler[PositionUnpickler](PositionsSection) { @@ -35,6 +35,10 @@ object DottyUnpickler { def unpickle(reader: TastyReader, nameAtRef: NameTable): CommentUnpickler = new CommentUnpickler(reader) } + class AttributesSectionUnpickler extends SectionUnpickler[AttributeUnpickler](AttributesSection) { + def unpickle(reader: TastyReader, nameAtRef: NameTable): AttributeUnpickler = + new AttributeUnpickler(reader) + } } /** A class for unpickling Tasty trees and symbols. @@ -48,7 +52,8 @@ class DottyUnpickler(bytes: Array[Byte], mode: UnpickleMode = UnpickleMode.TopLe val unpickler: TastyUnpickler = new TastyUnpickler(bytes) private val posUnpicklerOpt = unpickler.unpickle(new PositionsSectionUnpickler) private val commentUnpicklerOpt = unpickler.unpickle(new CommentsSectionUnpickler) - private val treeUnpickler = unpickler.unpickle(treeSectionUnpickler(posUnpicklerOpt, commentUnpicklerOpt)).get + private val attributeUnpicklerOpt = unpickler.unpickle(new AttributesSectionUnpickler) + private val treeUnpickler = unpickler.unpickle(treeSectionUnpickler(posUnpicklerOpt, commentUnpicklerOpt, attributeUnpicklerOpt)).get /** Enter all toplevel classes and objects into their scopes * @param roots a set of SymDenotations that should be overwritten by unpickling @@ -56,8 +61,12 @@ class DottyUnpickler(bytes: Array[Byte], mode: UnpickleMode = UnpickleMode.TopLe def enter(roots: Set[SymDenotation])(using Context): Unit = treeUnpickler.enter(roots) - protected def treeSectionUnpickler(posUnpicklerOpt: Option[PositionUnpickler], commentUnpicklerOpt: Option[CommentUnpickler]): TreeSectionUnpickler = - new TreeSectionUnpickler(posUnpicklerOpt, commentUnpicklerOpt) + protected def treeSectionUnpickler( + posUnpicklerOpt: Option[PositionUnpickler], + commentUnpicklerOpt: Option[CommentUnpickler], + attributeUnpicklerOpt: Option[AttributeUnpickler] + ): TreeSectionUnpickler = + new TreeSectionUnpickler(posUnpicklerOpt, commentUnpicklerOpt, attributeUnpicklerOpt) protected def computeRootTrees(using Context): List[Tree] = treeUnpickler.unpickle(mode) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/ScratchData.scala b/compiler/src/dotty/tools/dotc/core/tasty/ScratchData.scala index b36c78a77ac6..74cc6aaae533 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/ScratchData.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/ScratchData.scala @@ -10,6 +10,7 @@ class ScratchData: val pickledIndices = new mutable.BitSet val commentBuffer = new TastyBuffer(5000) + val attributeBuffer = new TastyBuffer(128) def reset() = assert(delta ne delta1) @@ -17,4 +18,5 @@ class ScratchData: positionBuffer.reset() pickledIndices.clear() commentBuffer.reset() + attributeBuffer.reset() diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala index 5876b69edfde..7f15831709b5 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala @@ -9,7 +9,7 @@ import Contexts._, Decorators._ import Names.Name import TastyUnpickler._ import util.Spans.offsetToInt -import dotty.tools.tasty.TastyFormat.{ASTsSection, PositionsSection, CommentsSection} +import dotty.tools.tasty.TastyFormat.{ASTsSection, PositionsSection, CommentsSection, AttributesSection} import java.nio.file.{Files, Paths} import dotty.tools.io.{JarArchive, Path} @@ -84,14 +84,16 @@ class TastyPrinter(bytes: Array[Byte]) { case Some(s) => sb.append(s) case _ => } - sb.append("\n\n") unpickle(new PositionSectionUnpickler) match { - case Some(s) => sb.append(s) + case Some(s) => sb.append("\n\n").append(s) case _ => } - sb.append("\n\n") unpickle(new CommentSectionUnpickler) match { - case Some(s) => sb.append(s) + case Some(s) => sb.append("\n\n").append(s) + case _ => + } + unpickle(new AttributesSectionUnpickler) match { + case Some(s) => sb.append("\n\n").append(s) case _ => } sb.result @@ -222,6 +224,20 @@ class TastyPrinter(bytes: Array[Byte]) { } } + class AttributesSectionUnpickler extends SectionUnpickler[String](AttributesSection) { + + private val sb: StringBuilder = new StringBuilder + + def unpickle(reader: TastyReader, tastyName: NameTable): String = { + sb.append(s" ${reader.endAddr.index - reader.currentAddr.index}") + val attributes = new AttributeUnpickler(reader).attributes + sb.append(s" attributes bytes:\n") + for attribute <- attributes do + sb.append(" ").append(attribute).append("\n") + sb.result + } + } + protected def nameStr(str: String): String = str protected def treeStr(str: String): String = str protected def lengthStr(str: String): String = str diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 7fa335afbf44..71d7f99c2ed2 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -52,11 +52,13 @@ import scala.annotation.internal.sharable * @param reader the reader from which to unpickle * @param posUnpicklerOpt the unpickler for positions, if it exists * @param commentUnpicklerOpt the unpickler for comments, if it exists + * @param attributeUnpicklerOpt the unpickler for attributes, if it exists */ class TreeUnpickler(reader: TastyReader, nameAtRef: NameTable, posUnpicklerOpt: Option[PositionUnpickler], - commentUnpicklerOpt: Option[CommentUnpickler]) { + commentUnpicklerOpt: Option[CommentUnpickler], + attributeUnpicklerOpt: Option[AttributeUnpickler]) { import TreeUnpickler._ import tpd._ diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index 252bb6daeae5..8976cd97c7a6 100644 --- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala +++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala @@ -108,6 +108,9 @@ class Pickler extends Phase { pickler, treePkl.buf.addrOfTree, treePkl.docString, tree, scratch.commentBuffer) + val attributes = Nil // TODO add attributes here + AttributePickler.pickleAttributes(attributes, pickler, scratch.attributeBuffer) + val pickled = pickler.assembleParts() def rawBytes = // not needed right now, but useful to print raw format. diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index d91295f06af5..4c37379a1e9c 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -267,6 +267,9 @@ Standard Section: "Comments" Comment* ```none Comment = Length Bytes LongInt // Raw comment's bytes encoded as UTF-8, followed by the comment's coordinates. ``` + +Standard Section: "Attributes" UTF8* + **************************************************************************************/ object TastyFormat { @@ -361,6 +364,7 @@ object TastyFormat { final val ASTsSection = "ASTs" final val PositionsSection = "Positions" final val CommentsSection = "Comments" + final val AttributesSection = "Attributes" /** Tags used to serialize names, should update [[TastyFormat$.nameTagToString]] if a new constant is added */ class NameTags {