diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala index 3a482309e0c3..d1c9904cf6cb 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala @@ -11,14 +11,52 @@ import TastyUnpickler._ import util.Spans.offsetToInt import printing.Highlighting._ import dotty.tools.tasty.TastyFormat.{ASTsSection, PositionsSection, CommentsSection} +import java.nio.file.{Files, Paths} +import dotty.tools.io.{JarArchive, Path} object TastyPrinter: - def show(bytes: Array[Byte])(using Context): String = + + def showContents(bytes: Array[Byte], noColor: Boolean): String = val printer = - if ctx.settings.color.value == "never" then new TastyPrinter(bytes) + if noColor then new TastyPrinter(bytes) else new TastyAnsiiPrinter(bytes) printer.showContents() + def main(args: Array[String]): Unit = { + // TODO: Decouple CliCommand from Context and use CliCommand.distill? + val lineWidth = 80 + val line = "-" * lineWidth + val noColor = args.contains("-color:never") + var printLastLine = false + def printTasty(fileName: String, bytes: Array[Byte]): Unit = + println(line) + println(fileName) + println(line) + println(showContents(bytes, noColor)) + println() + printLastLine = true + for arg <- args do + if arg == "-color:never" then () // skip + else if arg.startsWith("-") then println(s"bad option '$arg' was ignored") + else if arg.endsWith(".tasty") then { + val path = Paths.get(arg) + if Files.exists(path) then printTasty(arg, Files.readAllBytes(path)) + else println("File not found: " + arg) + } + else if arg.endsWith(".jar") then { + val jar = JarArchive.open(Path(arg), create = false) + try + for file <- jar.iterator() if file.name.endsWith(".tasty") do + printTasty(s"$arg ${file.path}", file.toByteArray) + finally jar.close() + + } + else println(s"Not a '.tasty' or '.jar' file: $arg") + + if printLastLine then + println(line) + } + class TastyPrinter(bytes: Array[Byte]) { private val sb: StringBuilder = new StringBuilder diff --git a/compiler/src/dotty/tools/dotc/decompiler/DecompilationPrinter.scala b/compiler/src/dotty/tools/dotc/decompiler/DecompilationPrinter.scala index 978ebb4416e3..55e6e54787a2 100644 --- a/compiler/src/dotty/tools/dotc/decompiler/DecompilationPrinter.scala +++ b/compiler/src/dotty/tools/dotc/decompiler/DecompilationPrinter.scala @@ -40,12 +40,8 @@ class DecompilationPrinter extends Phase { private def printToOutput(out: PrintStream)(using Context): Unit = { val unit = ctx.compilationUnit - if (ctx.settings.printTasty.value) - println(TastyPrinter.show(unit.pickled.head._2())) - else { - val unitFile = unit.source.toString.replace("\\", "/").replace(".class", ".tasty") - out.println(s"/** Decompiled from $unitFile */") - out.println(QuotesImpl.showDecompiledTree(unit.tpdTree)) - } + val unitFile = unit.source.toString.replace("\\", "/").replace(".class", ".tasty") + out.println(s"/** Decompiled from $unitFile */") + out.println(QuotesImpl.showDecompiledTree(unit.tpdTree)) } } diff --git a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala index dd8f45401188..0b323836d59a 100644 --- a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala @@ -174,7 +174,7 @@ object PickledQuotes { positionWarnings.foreach(report.warning(_)) val pickled = pickler.assembleParts() - quotePickling.println(s"**** pickled quote\n${TastyPrinter.show(pickled)}") + quotePickling.println(s"**** pickled quote\n${TastyPrinter.showContents(pickled, ctx.settings.color.value == "never")}") pickled } @@ -195,7 +195,7 @@ object PickledQuotes { case pickled: String => TastyString.unpickle(pickled) case pickled: List[String] => TastyString.unpickle(pickled) - quotePickling.println(s"**** unpickling quote from TASTY\n${TastyPrinter.show(bytes)}") + quotePickling.println(s"**** unpickling quote from TASTY\n${TastyPrinter.showContents(bytes, ctx.settings.color.value == "never")}") val mode = if (isType) UnpickleMode.TypeTree else UnpickleMode.Term val unpickler = new DottyUnpickler(bytes, mode) diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index 6805160dbf32..a7724b4a5a31 100644 --- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala +++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala @@ -91,7 +91,7 @@ class Pickler extends Phase { if pickling ne noPrinter then pickling.synchronized { println(i"**** pickled info of $cls") - println(TastyPrinter.show(pickled)) + println(TastyPrinter.showContents(pickled, ctx.settings.color.value == "never")) } pickled }(using ExecutionContext.global) diff --git a/compiler/test/dotty/tools/dotc/core/tasty/PathPicklingTest.scala b/compiler/test/dotty/tools/dotc/core/tasty/PathPicklingTest.scala index 2a44c681e8f1..927cbe838e6e 100644 --- a/compiler/test/dotty/tools/dotc/core/tasty/PathPicklingTest.scala +++ b/compiler/test/dotty/tools/dotc/core/tasty/PathPicklingTest.scala @@ -1,7 +1,7 @@ package dotty.tools.dotc.core.tasty import java.io.{File => JFile, ByteArrayOutputStream, IOException} -import java.nio.file.{Files, NoSuchFileException, Path, Paths} +import java.nio.file.{Files, NoSuchFileException, Paths} import scala.sys.process._ @@ -19,7 +19,7 @@ import dotty.tools.dotc.core.Mode import dotty.tools.dotc.core.Names.Name import dotty.tools.dotc.interfaces.Diagnostic.ERROR import dotty.tools.dotc.reporting.TestReporter -import dotty.tools.io.{Directory, File, Path} +import dotty.tools.io.{Directory, File, Path, JarArchive} import dotty.tools.vulpix.TestConfiguration @@ -42,28 +42,24 @@ class PathPicklingTest { assertFalse("Compilation failed.", rep.hasErrors) } - val decompiled = - val outstream = new ByteArrayOutputStream() - val options = TestConfiguration.defaultOptions - .and("-print-tasty") - .and("-color:never") - .and(s"$out/out.jar") - val reporter = TestReporter.reporter(System.out, logLevel = ERROR) - val rep = Console.withOut(outstream) { - decompiler.Main.process(options.all, reporter) - } - assertFalse("Decompilation failed.", rep.hasErrors) - new String(outstream.toByteArray(), "UTF-8") + val printedTasty = + val sb = new StringBuffer + val jar = JarArchive.open(Path(s"$out/out.jar"), create = false) + try + for file <- jar.iterator() if file.name.endsWith(".tasty") do + sb.append(TastyPrinter.showContents(file.toByteArray, noColor = true)) + finally jar.close() + sb.toString() - assertTrue(decompiled.contains(": i10430/lib.scala")) - assertTrue(decompiled.contains(": i10430/app.scala")) - assertTrue(decompiled.contains("[i10430/lib.scala]")) - assertTrue(decompiled.contains("[i10430/app.scala]")) + assertTrue(printedTasty.contains(": i10430/lib.scala")) + assertTrue(printedTasty.contains("[i10430/lib.scala]")) + assertFalse(printedTasty.contains(": i10430\\lib.scala")) + assertFalse(printedTasty.contains("[i10430\\lib.scala]")) - assertFalse(decompiled.contains(": i10430\\lib.scala")) - assertFalse(decompiled.contains(": i10430\\app.scala")) - assertFalse(decompiled.contains("[i10430\\lib.scala]")) - assertFalse(decompiled.contains("[i10430\\app.scala]")) + assertTrue(printedTasty.contains(": i10430/app.scala")) + assertTrue(printedTasty.contains("[i10430/app.scala]")) + assertFalse(printedTasty.contains(": i10430\\app.scala")) + assertFalse(printedTasty.contains("[i10430\\app.scala]")) } private def delete(file: JFile): Unit = { diff --git a/dist/bin/common b/dist/bin/common index 2826e9e06708..e3e4253938fb 100755 --- a/dist/bin/common +++ b/dist/bin/common @@ -200,6 +200,7 @@ default_java_opts="-Xmx768m -Xms768m" CompilerMain=dotty.tools.dotc.Main DecompilerMain=dotty.tools.dotc.decompiler.Main +TastyPrinterMain=dotty.tools.dotc.core.tasty.TastyPrinter ReplMain=dotty.tools.repl.Main ScriptingMain=dotty.tools.scripting.Main diff --git a/dist/bin/scalac b/dist/bin/scalac index 9a168316d16f..6ebf0fe70ea8 100644 --- a/dist/bin/scalac +++ b/dist/bin/scalac @@ -45,7 +45,7 @@ case "$1" in while [[ $# -gt 0 ]]; do addScript "$1" && shift ; done ;; -compile) PROG_NAME="$CompilerMain" && shift ;; -decompile) PROG_NAME="$DecompilerMain" && shift ;; - -print-tasty) PROG_NAME="$DecompilerMain" && addScala "-print-tasty" && shift ;; + -print-tasty) PROG_NAME="$TastyPrinterMain" && shift ;; -run) PROG_NAME="$ReplMain" && shift ;; -colors) colors=true && shift ;; -no-colors) unset colors && shift ;; diff --git a/project/Build.scala b/project/Build.scala index 2e5b15abf555..6442cf944c0c 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -640,16 +640,17 @@ object Build { val printTasty = args0.contains("-print-tasty") val debugFromTasty = args0.contains("-Ythrough-tasty") val args = args0.filter(arg => arg != "-repl" && arg != "-decompile" && - arg != "-with-compiler" && arg != "-Ythrough-tasty") + arg != "-with-compiler" && arg != "-Ythrough-tasty" && arg != "-print-tasty") val main = - if (decompile || printTasty) "dotty.tools.dotc.decompiler.Main" + if (decompile) "dotty.tools.dotc.decompiler.Main" + else if (printTasty) "dotty.tools.dotc.core.tasty.TastyPrinter" else if (debugFromTasty) "dotty.tools.dotc.fromtasty.Debug" else "dotty.tools.dotc.Main" var extraClasspath = Seq(scalaLib, dottyLib) - if ((decompile || printTasty) && !args.contains("-classpath")) + if (decompile && !args.contains("-classpath")) extraClasspath ++= Seq(".") if (args0.contains("-with-compiler")) { @@ -664,7 +665,7 @@ object Build { extraClasspath ++= Seq(dottyCompiler, dottyInterfaces, asm, dottyStaging, dottyTastyInspector, tastyCore) } - val fullArgs = main :: insertClasspathInArgs(args, extraClasspath.mkString(File.pathSeparator)) + val fullArgs = main :: (if (printTasty) args else insertClasspathInArgs(args, extraClasspath.mkString(File.pathSeparator))) (Compile / runMain).toTask(fullArgs.mkString(" ", " ", "")) }.evaluated, diff --git a/project/scripts/cmdTests b/project/scripts/cmdTests index 37bb8bcb706e..e486b0f5cc50 100755 --- a/project/scripts/cmdTests +++ b/project/scripts/cmdTests @@ -23,10 +23,16 @@ clear_out "$OUT" "$SBT" ";scalac $SOURCE ; scala $MAIN" > "$tmp" grep -qe "$EXPECTED_OUTPUT" "$tmp" +echo "testing sbt scalac -print-tasty" +clear_out "$OUT" +"$SBT" ";scalac $SOURCE -d $OUT ;scalac -print-tasty -color:never $TASTY" > "$tmp" +grep -qe "0: ASTs" "$tmp" +grep -qe "0: tests/pos/HelloWorld.scala" "$tmp" + echo "testing that paths SourceFile annotations are relativized" clear_out "$OUT" "$SBT" "scalac -d $OUT/out.jar -sourceroot tests/pos $(pwd)/tests/pos/i10430/lib.scala $(pwd)/tests/pos/i10430/app.scala" -"$SBT" "scalac -decompile -print-tasty -color:never $OUT/out.jar" > "$tmp" +"$SBT" "scalac -print-tasty -color:never $OUT/out.jar" > "$tmp" cat "$tmp" # for debugging grep -q ": i10430/lib.scala" "$tmp" grep -q ": i10430/app.scala" "$tmp" @@ -82,3 +88,5 @@ clear_out "$OUT" # fi # fi # done 3<"$tmp1" 4<"./tests/vulpix-tests/meta/sbt-output.check" + +echo "cmdTests successful"