Skip to content

Commit

Permalink
Create dotc decompiler
Browse files Browse the repository at this point in the history
* `dotc -decompile <options|classes>*`
  • Loading branch information
nicolasstucki committed Nov 20, 2017
1 parent cc43c34 commit 4790d75
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 11 deletions.
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/CompilationUnit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ object CompilationUnit {
/** Make a compilation unit for top class `clsd` with the contends of the `unpickled` */
def mkCompilationUnit(clsd: ClassDenotation, unpickled: Tree, forceTrees: Boolean)(implicit ctx: Context): CompilationUnit = {
assert(!unpickled.isEmpty, unpickled)
val unit1 = new CompilationUnit(new SourceFile(clsd.symbol.sourceFile, Seq()))
val unit1 = new CompilationUnit(new SourceFile(clsd.symbol.associatedFile, Seq()))
unit1.tpdTree = unpickled
if (forceTrees)
force.traverse(unit1.tpdTree)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package dotty.tools.dotc
package decompiler

import dotty.tools.dotc.core.Contexts._
import dotty.tools.dotc.core.Phases.Phase

/** Phase that prints the trees in all loaded compilation units.
*
* @author Nicolas Stucki
*/
class DecompilationPrinter extends Phase {

override def phaseName: String = "decompilationPrinter"

override def run(implicit ctx: Context): Unit = {
val unit = ctx.compilationUnit

val pageWidth = ctx.settings.pageWidth.value

val doubleLine = "=" * pageWidth
val line = "-" * pageWidth

println(doubleLine)
println(unit.source)
println(line)

val code = unit.tpdTree.show
println(if (ctx.useColors) printing.SyntaxHighlighting(code) else code)
println(line)
}
}
21 changes: 21 additions & 0 deletions compiler/src/dotty/tools/dotc/decompiler/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package dotty.tools.dotc.decompiler

import dotty.tools.dotc
import dotty.tools.dotc.core.Contexts._

/** Main class of the `dotc -decompiler` decompiler.
*
* @author Nicolas Stucki
*/
object Main extends dotc.Driver {
override protected def newCompiler(implicit ctx: Context): dotc.Compiler = {
assert(ctx.settings.fromTasty.value)
new TASTYDecompiler
}

override def setup(args0: Array[String], rootCtx: Context): (List[String], Context) = {
var args = args0.filter(a => a != "-decompile")
args = if (args.contains("-from-tasty")) args else "-from-tasty" +: args
super.setup(args, rootCtx)
}
}
16 changes: 16 additions & 0 deletions compiler/src/dotty/tools/dotc/decompiler/TASTYDecompiler.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package dotty.tools.dotc.decompiler

import dotty.tools.dotc.fromtasty._
import dotty.tools.dotc.core.Phases.Phase

/** Compiler from tasty to user readable high text representation
* of the compiled scala code.
*
* @author Nicolas Stucki
*/
class TASTYDecompiler extends TASTYCompiler {
override def phases: List[List[Phase]] = List(
List(new ReadTastyTreesFromClasses), // Load classes from tasty
List(new DecompilationPrinter) // Print all loaded classes
)
}
2 changes: 2 additions & 0 deletions dist/bin/dotc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ default_java_opts="-Xmx768m -Xms768m"
bootcp=true

CompilerMain=dotty.tools.dotc.Main
DecompilerMain=dotty.tools.dotc.decompiler.Main
ReplMain=dotty.tools.repl.Main

PROG_NAME=$CompilerMain
Expand Down Expand Up @@ -82,6 +83,7 @@ case "$1" in
-Oshort) addJava "-XX:+TieredCompilation -XX:TieredStopAtLevel=1" && shift ;;
-repl) PROG_NAME="$ReplMain" && shift ;;
-compile) PROG_NAME="$CompilerMain" && shift ;;
-decompile) PROG_NAME="$DecompilerMain" && shift ;;
-run) PROG_NAME="$ReplMain" && shift ;;
-bootcp) bootcp=true && shift ;;
-nobootcp) unset bootcp && shift ;;
Expand Down
17 changes: 12 additions & 5 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ object Build {
lazy val dotr =
inputKey[Unit]("run compiled binary using the correct classpath, or the user supplied classpath")


// Compiles the documentation and static site
lazy val genDocs = taskKey[Unit]("run dottydoc to generate static documentation site")

Expand Down Expand Up @@ -523,8 +524,8 @@ object Build {
}
},
run := dotc.evaluated,
dotc := runCompilerMain(false).evaluated,
repl := runCompilerMain(true).evaluated,
dotc := runCompilerMain().evaluated,
repl := runCompilerMain(repl = true).evaluated,

// enable verbose exception messages for JUnit
testOptions in Test += Tests.Argument(
Expand Down Expand Up @@ -618,16 +619,22 @@ object Build {
}
)

def runCompilerMain(repl: Boolean) = Def.inputTaskDyn {
def runCompilerMain(repl: Boolean = false) = Def.inputTaskDyn {
val dottyLib = packageAll.value("dotty-library")
val args0: List[String] = spaceDelimited("<arg>").parsed.toList
val args = args0.filter(arg => arg != "-repl")
val decompile = args0.contains("-decompile")
val args = args0.filter(arg => arg != "-repl" || arg != "-decompile")

val main =
if (repl) "dotty.tools.repl.Main"
else if (decompile) "dotty.tools.dotc.decompiler.Main"
else "dotty.tools.dotc.Main"

val fullArgs = main :: insertClasspathInArgs(args, dottyLib)
val extraClasspath =
if (decompile && !args.contains("-classpath")) dottyLib + ":."
else dottyLib

val fullArgs = main :: insertClasspathInArgs(args, extraClasspath)

(runMain in Compile).toTask(fullArgs.mkString(" ", " ", ""))
}
Expand Down
4 changes: 2 additions & 2 deletions project/scripts/sbtBootstrappedTests
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
./project/scripts/sbt dist-bootstrapped/pack

# check that `dotc` compiles and `dotr` runs it
echo "testing sbt dotc and dotr"
echo "testing ./bin/dotc and ./bin/dotr"
mkdir out/scriptedtest0
./bin/dotc tests/pos/sbtDotrTest.scala -d out/scriptedtest0
# FIXME #3477
Expand All @@ -21,7 +21,7 @@ mkdir out/scriptedtest0


# check that `dotc` compiles and `dotr` runs it
echo "testing sbt dotc -from-tasty and dotr -classpath"
echo "testing ./bin/dotc -from-tasty and dotr -classpath"
mkdir out/scriptedtest1
mkdir out/scriptedtest2
./bin/dotc tests/pos/sbtDotrTest.scala -d out/scriptedtest1/
Expand Down
19 changes: 16 additions & 3 deletions project/scripts/sbtTests
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ cat sbtdotr1.out
if grep -e "dotr test ok" sbtdotr1.out; then
echo "output ok"
else
echo "failed output check"
exit -1
fi

Expand All @@ -23,13 +24,25 @@ cat sbtdotr2.out
if grep -e "dotr test ok" sbtdotr2.out; then
echo "output ok"
else
echo "failed output check"
exit -1
fi

# check that `sbt dotc -decompile` runs
echo "testing sbt dotc -decompile"
./project/scripts/sbt ";dotc -decompile -code -color:never -classpath out/scriptedtest1 dotrtest.Test" > sbtdotc3.out
cat sbtdotc3.out
if grep -e "def main(args: Array\[String\]): Unit =" sbtdotc3.out; then
echo "output ok"
else
echo "failed output check"
exit -1
fi
echo "testing sbt dotr with no -classpath"

./project/scripts/sbt ";dotc tests/pos/sbtDotrTest.scala; dotr dotrtest.Test" > sbtdotp1.out
cat sbtdotp1.out
if grep -e "dotr test ok" sbtdotp1.out; then
./project/scripts/sbt ";dotc tests/pos/sbtDotrTest.scala; dotr dotrtest.Test" > sbtdotr3.out
cat sbtdotr3.out
if grep -e "dotr test ok" sbtdotr3.out; then
echo "output ok"
else
exit -1
Expand Down

0 comments on commit 4790d75

Please sign in to comment.