Skip to content

Commit 30b8b1c

Browse files
Merge pull request #5325 from dotty-staging/add-tasty-file-input
Allow tasty files to be the input of -from-tasty
2 parents 74c405e + 0bf8b17 commit 30b8b1c

File tree

6 files changed

+133
-5
lines changed

6 files changed

+133
-5
lines changed

compiler/src/dotty/tools/dotc/Driver.scala

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package dotty.tools.dotc
22

3+
import java.nio.file.{Files, Paths}
4+
35
import dotty.tools.FatalError
46
import config.CompilerCommand
57
import core.Comments.{ContextDoc, ContextDocstrings}
68
import core.Contexts.{Context, ContextBase}
79
import core.Mode
810
import reporting._
11+
912
import scala.util.control.NonFatal
10-
import fromtasty.TASTYCompiler
13+
import fromtasty.{TASTYCompiler, TastyFileUtil}
1114

1215
/** Run the Dotty compiler.
1316
*
@@ -54,7 +57,34 @@ class Driver {
5457
}
5558

5659
val fileNames = CompilerCommand.checkUsage(summary, sourcesRequired)(ctx)
57-
(fileNames, ctx)
60+
fromTastySetup(fileNames, ctx)
61+
}
62+
63+
/** Setup extra classpath and figure out class names for tasty file inputs */
64+
private def fromTastySetup(fileNames0: List[String], ctx0: Context) = {
65+
if (ctx0.settings.fromTasty.value(ctx0)) {
66+
// Resolve classpath and class names of tasty files
67+
val (classPaths, classNames) = fileNames0.map { name =>
68+
val path = Paths.get(name)
69+
if (!name.endsWith(".tasty")) ("", name)
70+
else if (Files.exists(path)) {
71+
TastyFileUtil.getClassName(path) match {
72+
case Some(res) => res
73+
case _ =>
74+
ctx0.error(s"Could not load classname from $name.")
75+
("", name)
76+
}
77+
} else {
78+
ctx0.error(s"File $name does not exist.")
79+
("", name)
80+
}
81+
}.unzip
82+
val ctx1 = ctx0.fresh
83+
val classPaths1 = classPaths.distinct.filter(_ != "")
84+
val fullClassPath = (classPaths1 :+ ctx1.settings.classpath.value(ctx1)).mkString(java.io.File.pathSeparator)
85+
ctx1.setSetting(ctx1.settings.classpath, fullClassPath)
86+
(classNames, ctx1)
87+
} else (fileNames0, ctx0)
5888
}
5989

6090
/** Entry point to the compiler that can be conveniently used with Java reflection.

compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ object DottyUnpickler {
1616
class BadSignature(msg: String) extends RuntimeException(msg)
1717

1818
class TreeSectionUnpickler(posUnpickler: Option[PositionUnpickler], commentUnpickler: Option[CommentUnpickler])
19-
extends SectionUnpickler[TreeUnpickler]("ASTs") {
19+
extends SectionUnpickler[TreeUnpickler](TreePickler.sectionName) {
2020
def unpickle(reader: TastyReader, nameAtRef: NameTable): TreeUnpickler =
2121
new TreeUnpickler(reader, nameAtRef, posUnpickler, commentUnpickler, Seq.empty)
2222
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package dotty.tools.dotc
2+
package core
3+
package tasty
4+
5+
import Contexts._, Decorators._
6+
import Names.{Name, TermName}
7+
import StdNames.nme
8+
import TastyUnpickler._
9+
import TastyBuffer.NameRef
10+
import util.Positions.offsetToInt
11+
import printing.Highlighting._
12+
13+
/** Reads the package and class name of the class contained in this TASTy */
14+
class TastyClassName(bytes: Array[Byte]) {
15+
16+
val unpickler: TastyUnpickler = new TastyUnpickler(bytes)
17+
import unpickler.{nameAtRef, unpickle}
18+
19+
/** Returns a tuple with the package and class names */
20+
def readName(): Option[(TermName, TermName)] = unpickle(new TreeSectionUnpickler)
21+
22+
class TreeSectionUnpickler extends SectionUnpickler[(TermName, TermName)](TreePickler.sectionName) {
23+
import TastyFormat._
24+
def unpickle(reader: TastyReader, tastyName: NameTable): (TermName, TermName) = {
25+
import reader._
26+
def readName() = {
27+
val idx = readNat()
28+
nameAtRef(NameRef(idx))
29+
}
30+
def readNames(packageName: TermName): (TermName, TermName) = {
31+
val tag = readByte()
32+
if (tag >= firstLengthTreeTag) {
33+
val len = readNat()
34+
val end = currentAddr + len
35+
tag match {
36+
case TYPEDEF =>
37+
val className = readName()
38+
goto(end)
39+
(packageName, className)
40+
case IMPORT | VALDEF =>
41+
goto(end)
42+
readNames(packageName)
43+
case PACKAGE =>
44+
readNames(packageName)
45+
}
46+
}
47+
else tag match {
48+
case TERMREFpkg | TYPEREFpkg =>
49+
val subPackageName = readName()
50+
readNames(subPackageName)
51+
case _ =>
52+
readNames(packageName)
53+
}
54+
}
55+
readNames(nme.EMPTY_PACKAGE)
56+
}
57+
}
58+
}

compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) {
3434
unpickle(new CommentSectionUnpickler)
3535
}
3636

37-
class TreeSectionUnpickler extends SectionUnpickler[Unit]("ASTs") {
37+
class TreeSectionUnpickler extends SectionUnpickler[Unit](TreePickler.sectionName) {
3838
import TastyFormat._
3939
def unpickle(reader: TastyReader, tastyName: NameTable): Unit = {
4040
import reader._

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import printing.Texts._
1717

1818
object TreePickler {
1919

20+
val sectionName = "ASTs"
21+
2022
case class Hole(idx: Int, args: List[tpd.Tree]) extends tpd.Tree {
2123
override def fallbackToText(printer: Printer): Text =
2224
s"[[$idx|" ~~ printer.toTextGlobal(args, ", ") ~~ "]]"
@@ -25,7 +27,7 @@ object TreePickler {
2527

2628
class TreePickler(pickler: TastyPickler) {
2729
val buf: TreeBuffer = new TreeBuffer
28-
pickler.newSection("ASTs", buf)
30+
pickler.newSection(TreePickler.sectionName, buf)
2931
import TreePickler._
3032
import buf._
3133
import pickler.nameBuffer.nameIndex
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package dotty.tools.dotc
2+
package fromtasty
3+
4+
import java.nio.file.{Files, Path, Paths}
5+
import java.io
6+
7+
import dotty.tools.dotc.core.Contexts.Context
8+
import dotty.tools.dotc.core.NameKinds
9+
import dotty.tools.dotc.core.Names.SimpleName
10+
import dotty.tools.dotc.core.StdNames.nme
11+
import dotty.tools.dotc.core.tasty.{TastyUnpickler, TreePickler}
12+
13+
object TastyFileUtil {
14+
15+
/** Get the class path and the class name including packages
16+
*
17+
* If
18+
* ```scala
19+
* package foo
20+
* class Foo
21+
* ```
22+
* then `getClassName("./out/foo/Foo.tasty") returns `Some(("./out", "foo.Foo"))`
23+
*/
24+
def getClassName(path: Path): Option[(String, String)] = {
25+
assert(path.toString.endsWith(".tasty"))
26+
assert(Files.exists(path))
27+
val bytes = Files.readAllBytes(path)
28+
val names = new core.tasty.TastyClassName(bytes).readName()
29+
names.map { case (packageName, className) =>
30+
val fullName = s"$packageName.${className.lastPart}"
31+
val classInPath = fullName.replace(".", io.File.separator) + ".tasty"
32+
val classpath = path.toString.replace(classInPath, "")
33+
(classpath, fullName)
34+
}
35+
36+
}
37+
38+
}

0 commit comments

Comments
 (0)