Skip to content

Commit 60e1a38

Browse files
committed
Create dotp decompiler
1 parent faedad7 commit 60e1a38

File tree

10 files changed

+149
-8
lines changed

10 files changed

+149
-8
lines changed

bin/dotp

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env bash
2+
3+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" >& /dev/null && pwd)/.."
4+
5+
eval "$ROOT/bin/common" "$ROOT/dist-bootstrapped/target/pack/bin/dotp" "$@"

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ object CompilationUnit {
2828
/** Make a compilation unit for top class `clsd` with the contends of the `unpickled` */
2929
def mkCompilationUnit(clsd: ClassDenotation, unpickled: Tree, forceTrees: Boolean)(implicit ctx: Context): CompilationUnit = {
3030
assert(!unpickled.isEmpty, unpickled)
31-
val unit1 = new CompilationUnit(new SourceFile(clsd.symbol.sourceFile, Seq()))
31+
val unit1 = new CompilationUnit(new SourceFile(clsd.symbol.associatedFile, Seq()))
3232
unit1.tpdTree = unpickled
3333
if (forceTrees)
3434
force.traverse(unit1.tpdTree)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package dotty.tools.dotp
2+
3+
import dotty.tools.dotc.core.Contexts._
4+
import dotty.tools.dotc.core.Phases.Phase
5+
6+
/** Phase that prints the trees in all loaded compilation units.
7+
*
8+
* @author Nicolas Stucki
9+
*/
10+
class DecompilationPrinter extends Phase {
11+
12+
override def phaseName: String = "decompilationPrinter"
13+
14+
override def run(implicit ctx: Context): Unit = println(output)
15+
16+
private def output(implicit ctx: Context): String = {
17+
val unit = ctx.compilationUnit
18+
// TODO add colors
19+
s"""${"=" * 80}
20+
|$unit
21+
|${"-" * 80}
22+
|${unit.tpdTree.show}
23+
|${"-" * 80}
24+
""".stripMargin
25+
}
26+
}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package dotty.tools.dotp
2+
3+
import dotty.tools.dotc
4+
import dotty.tools.dotc.core.Contexts._
5+
6+
/** Main class of the `dotp` decompiler.
7+
*
8+
* @author Nicolas Stucki
9+
*/
10+
object Main extends dotc.Driver {
11+
override protected def newCompiler(implicit ctx: Context): dotc.Compiler = {
12+
assert(ctx.settings.tasty.value)
13+
new TASTYDecompiler
14+
}
15+
16+
override def setup(args: Array[String], rootCtx: Context): (List[String], Context) = {
17+
val args1 = if (args.contains("-tasty")) args else args :+ "-tasty"
18+
super.setup(args1, rootCtx)
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package dotty.tools.dotp
2+
3+
import dotty.tools.dotc.fromtasty._
4+
import dotty.tools.dotc.core.Phases.Phase
5+
6+
/** Compiler from tasty to user readable high text representation
7+
* of the compiled scala code.
8+
*
9+
* @author Nicolas Stucki
10+
*/
11+
class TASTYDecompiler extends TASTYCompiler {
12+
override def phases: List[List[Phase]] = List(
13+
List(new ReadTastyTreesFromClasses), // Load classes from tasty
14+
List(new DecompilationPrinter) // Print all loaded classes
15+
)
16+
}

dist/bin/dotc

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ default_java_opts="-Xmx768m -Xms768m"
3131
bootcp=true
3232

3333
CompilerMain=dotty.tools.dotc.Main
34+
DecompilerMain=dotty.tools.dotp.Main
3435
ReplMain=dotty.tools.repl.Main
3536

3637
PROG_NAME=$CompilerMain
@@ -82,6 +83,7 @@ case "$1" in
8283
-Oshort) addJava "-XX:+TieredCompilation -XX:TieredStopAtLevel=1" && shift ;;
8384
-repl) PROG_NAME="$ReplMain" && shift ;;
8485
-compile) PROG_NAME="$CompilerMain" && shift ;;
86+
-decompile) PROG_NAME="$DecompilerMain" && shift ;;
8587
-run) PROG_NAME="$ReplMain" && shift ;;
8688
-bootcp) bootcp=true && shift ;;
8789
-nobootcp) unset bootcp && shift ;;

dist/bin/dotp

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
3+
# Try to autodetect real location of the script
4+
5+
if [ -z "$PROG_HOME" ] ; then
6+
## resolve links - $0 may be a link to PROG_HOME
7+
PRG="$0"
8+
9+
# need this for relative symlinks
10+
while [ -h "$PRG" ] ; do
11+
ls=`ls -ld "$PRG"`
12+
link=`expr "$ls" : '.*-> \(.*\)$'`
13+
if expr "$link" : '/.*' > /dev/null; then
14+
PRG="$link"
15+
else
16+
PRG="`dirname "$PRG"`/$link"
17+
fi
18+
done
19+
20+
saveddir=`pwd`
21+
22+
PROG_HOME=`dirname "$PRG"`/..
23+
24+
# make it fully qualified
25+
PROG_HOME=`cd "$PROG_HOME" && pwd`
26+
27+
cd "$saveddir"
28+
fi
29+
30+
source "$PROG_HOME/bin/common"
31+
32+
CLASS_PATH=".$PSEP$DOTTY_LIB$PSEP$SCALA_LIB"
33+
34+
# -d must be the first option
35+
case "$1" in
36+
-d) DEBUG="$DEBUG_STR" && shift ;;
37+
esac
38+
39+
first_arg="$1"
40+
41+
eval "$PROG_HOME/bin/dotc -decompile $@"

project/Build.scala

+13-4
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ object Build {
8787
lazy val dotr =
8888
inputKey[Unit]("run compiled binary using the correct classpath, or the user supplied classpath")
8989

90+
lazy val dotp =
91+
inputKey[Unit]("run the decompiler using the correct classpath, or the user supplied classpath")
92+
9093
// Compiles the documentation and static site
9194
lazy val genDocs = taskKey[Unit]("run dottydoc to generate static documentation site")
9295

@@ -523,8 +526,9 @@ object Build {
523526
}
524527
},
525528
run := dotc.evaluated,
526-
dotc := runCompilerMain(false).evaluated,
527-
repl := runCompilerMain(true).evaluated,
529+
dotc := runCompilerMain().evaluated,
530+
dotp := runCompilerMain(dotp = true).evaluated,
531+
repl := runCompilerMain(repl = true).evaluated,
528532

529533
// enable verbose exception messages for JUnit
530534
testOptions in Test += Tests.Argument(
@@ -618,16 +622,21 @@ object Build {
618622
}
619623
)
620624

621-
def runCompilerMain(repl: Boolean) = Def.inputTaskDyn {
625+
def runCompilerMain(repl: Boolean = false, dotp: Boolean = false) = Def.inputTaskDyn {
622626
val dottyLib = packageAll.value("dotty-library")
623627
val args0: List[String] = spaceDelimited("<arg>").parsed.toList
624628
val args = args0.filter(arg => arg != "-repl")
625629

626630
val main =
627631
if (repl) "dotty.tools.repl.Main"
632+
else if (dotp) "dotty.tools.dotp.Main"
628633
else "dotty.tools.dotc.Main"
629634

630-
val fullArgs = main :: insertClasspathInArgs(args, dottyLib)
635+
val extraClasspath =
636+
if (dotp && !args.contains("-classpath")) dottyLib + ":."
637+
else dottyLib
638+
639+
val fullArgs = main :: insertClasspathInArgs(args, extraClasspath)
631640

632641
(runMain in Compile).toTask(fullArgs.mkString(" ", " ", ""))
633642
}

project/scripts/sbtBootstrappedTests

+13-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
./project/scripts/sbt "dotty-bench-bootstrapped/jmh:run 1 1 tests/pos/alias.scala"
55

66

7-
# setup for `dotc`/`dotr` script tests
7+
# setup for `dotc`/`dotr`/`dotp` script tests
88
./project/scripts/sbt dist-bootstrapped/pack
99

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

2222

2323
# check that `dotc` compiles and `dotr` runs it
24-
echo "testing sbt dotc -tasty and dotr -classpath"
24+
echo "testing ./bin/dotc -tasty and dotr -classpath"
2525
mkdir out/scriptedtest1
2626
mkdir out/scriptedtest2
2727
./bin/dotc tests/pos/sbtDotrTest.scala -d out/scriptedtest1/
@@ -33,3 +33,13 @@ mkdir out/scriptedtest2
3333
#else
3434
# exit -1
3535
#fi
36+
37+
# check that `dotp` runs
38+
echo "testing ./bin/dotp"
39+
./bin/dotp -classpath out/scriptedtest1 dotrtest.Test > sbtdotr3.out
40+
if grep -e "def main(args: Array\[String\]): Unit =" sbtdotr3.out; then
41+
echo "output ok"
42+
else
43+
echo "failed output check"
44+
exit -1
45+
fi

project/scripts/sbtTests

+12
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mkdir out/scriptedtest0
1010
if grep -e "dotr test ok" sbtdotr1.out; then
1111
echo "output ok"
1212
else
13+
echo "failed output check"
1314
exit -1
1415
fi
1516

@@ -21,5 +22,16 @@ mkdir out/scriptedtest2
2122
if grep -e "dotr test ok" sbtdotr2.out; then
2223
echo "output ok"
2324
else
25+
echo "failed output check"
26+
exit -1
27+
fi
28+
29+
# check that `sbt dotp` runs
30+
echo "testing sbt dotp"
31+
./project/scripts/sbt ";dotp -tasty -classpath out/scriptedtest1 dotrtest.Test" > sbtdotr3.out
32+
if grep -e "def main(args: Array\[String\]): Unit =" sbtdotr3.out; then
33+
echo "output ok"
34+
else
35+
echo "failed output check"
2436
exit -1
2537
fi

0 commit comments

Comments
 (0)