Skip to content

Commit e416b3a

Browse files
committed
wip
1 parent 78787be commit e416b3a

15 files changed

+196
-290
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package dotty.tools.dotc
2+
package decompiler
3+
4+
import java.io.{OutputStream, PrintStream}
5+
6+
import dotty.tools.dotc.core.Contexts._
7+
import dotty.tools.dotc.core.Phases.Phase
8+
import dotty.tools.dotc.core.tasty.TastyPrinter
9+
import dotty.tools.dotc.printing.DecompilerPrinter
10+
import dotty.tools.dotc.tasty.TastyImpl
11+
import dotty.tools.io.{File, Path}
12+
13+
/** Phase that prints the trees in all loaded compilation units.
14+
*
15+
* @author Nicolas Stucki
16+
*/
17+
class DecompilationPrinter extends Phase {
18+
19+
override def phaseName: String = "decompilationPrinter"
20+
21+
override def run(implicit ctx: Context): Unit = {
22+
val outputDir = ctx.settings.outputDir.value
23+
if (outputDir == ".") printToOutput(System.out)
24+
else {
25+
var os: OutputStream = null
26+
var ps: PrintStream = null
27+
try {
28+
os = File(outputDir + "/decompiled.scala").outputStream(append = true)
29+
ps = new PrintStream(os)
30+
printToOutput(ps)
31+
} finally {
32+
if (os ne null) os.close()
33+
if (ps ne null) ps.close()
34+
}
35+
}
36+
}
37+
38+
private def printToOutput(out: PrintStream)(implicit ctx: Context): Unit = {
39+
val unit = ctx.compilationUnit
40+
41+
out.println(s"/** Decompiled from $unit */")
42+
TastyImpl.showSourceCode.showTree(unit.tpdTree)(ctx)
43+
44+
if (ctx.settings.printTasty.value) {
45+
out.println("/*")
46+
new TastyPrinter(unit.pickled.head._2).printContents()
47+
out.println("*/")
48+
}
49+
}
50+
}

compiler/src/dotty/tools/dotc/decompiler/Main.scala

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,7 @@ object Main extends dotc.Driver {
1515
val outputDir = ctx.settings.outputDir.value
1616
if (outputDir != ".")
1717
Files.deleteIfExists(Paths.get(outputDir + "/decompiled.scala"))
18-
new TASTYDecompiler(
19-
ctx.settings.pageWidth.value,
20-
ctx.settings.printLines.value,
21-
ctx.settings.printTasty.value,
22-
outputDir
23-
)
18+
new TASTYDecompiler
2419
}
2520

2621
override def setup(args0: Array[String], rootCtx: Context): (List[String], Context) = {
Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,23 @@
11
package dotty.tools.dotc.decompiler
22

3-
import java.io.{OutputStream, PrintStream}
4-
5-
import dotty.tools.dotc.ast.tpd
6-
import dotty.tools.dotc.core.Contexts
7-
import dotty.tools.dotc.core.Contexts.Context
8-
import dotty.tools.dotc.core.tasty.TastyPrinter
9-
import dotty.tools.dotc.printing.DecompilerPrinter
10-
import dotty.tools.dotc.tasty.{TASTYReflector, TastyImpl}
11-
import dotty.tools.io.File
3+
import dotty.tools.dotc.fromtasty._
4+
import dotty.tools.dotc.core.Phases.Phase
125

136
/** Compiler from tasty to user readable high text representation
147
* of the compiled scala code.
158
*
169
* @author Nicolas Stucki
1710
*/
18-
class TASTYDecompiler(pageWidth: Int, printLines: Boolean, printTasty: Boolean, outputDir: String) extends TASTYReflector {
19-
20-
override def reflect(tree: tpd.Tree)(implicit ctx: Contexts.Context): Unit = {
21-
if (outputDir == ".") printToOutput(System.out, tree)
22-
else {
23-
var os: OutputStream = null
24-
var ps: PrintStream = null
25-
try {
26-
os = File(outputDir + "/decompiled.scala").outputStream(append = true)
27-
ps = new PrintStream(os)
28-
printToOutput(ps, tree)
29-
} finally {
30-
if (os ne null) os.close()
31-
if (ps ne null) ps.close()
32-
}
33-
}
34-
}
11+
class TASTYDecompiler extends TASTYCompiler {
3512

36-
private def printToOutput(out: PrintStream, tree: tpd.Tree)(implicit ctx: Context): Unit = {
37-
val unit = ctx.compilationUnit
13+
override protected def frontendPhases: List[List[Phase]] =
14+
List(new ReadTastyTreesFromClasses) :: // Load classes from tasty
15+
Nil
3816

39-
out.println(s"/** Decompiled from $unit */")
40-
out.print(TastyImpl.showSourceCode.showTree(tree))
17+
override protected def picklerPhases: List[List[Phase]] = Nil
18+
override protected def transformPhases: List[List[Phase]] = Nil
4119

42-
if (printTasty) { // TODO split decompiler from -print-tasty
43-
out.println("/*")
44-
new TastyPrinter(unit.pickled.head._2).printContents()
45-
out.println("*/")
46-
}
47-
}
20+
override protected def backendPhases: List[List[Phase]] =
21+
List(new DecompilationPrinter) :: // Print all loaded classes
22+
Nil
4823
}

compiler/src/dotty/tools/dotc/quoted/ExprCompilationFrontend.scala

Lines changed: 0 additions & 54 deletions
This file was deleted.

compiler/src/dotty/tools/dotc/quoted/ExprCompiler.scala

Lines changed: 0 additions & 40 deletions
This file was deleted.

compiler/src/dotty/tools/dotc/quoted/ExprReflector.scala

Lines changed: 0 additions & 21 deletions
This file was deleted.

compiler/src/dotty/tools/dotc/quoted/ExprRun.scala

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package dotty.tools.dotc
2+
package quoted
3+
4+
import dotty.tools.backend.jvm.GenBCode
5+
import dotty.tools.dotc.ast.tpd
6+
import dotty.tools.dotc.core.Contexts.Context
7+
import dotty.tools.dotc.core.Decorators._
8+
import dotty.tools.dotc.core.Flags._
9+
import dotty.tools.dotc.core.Mode
10+
import dotty.tools.dotc.core.Names.TypeName
11+
import dotty.tools.dotc.core.Phases.Phase
12+
import dotty.tools.dotc.core.Scopes.{EmptyScope, newScope}
13+
import dotty.tools.dotc.core.StdNames.nme
14+
import dotty.tools.dotc.core.Symbols.defn
15+
import dotty.tools.dotc.core.Types.ExprType
16+
import dotty.tools.dotc.core.quoted.PickledQuotes
17+
import dotty.tools.dotc.transform.ReifyQuotes
18+
import dotty.tools.dotc.typer.FrontEnd
19+
import dotty.tools.dotc.util.Positions.Position
20+
import dotty.tools.dotc.util.SourceFile
21+
import dotty.tools.io.{AbstractFile, Path, PlainFile}
22+
23+
import scala.quoted.{Expr, Type}
24+
25+
/** Compiler that takes the contents of a quoted expression `expr` and produces
26+
* a class file with `class ' { def apply: Object = expr }`.
27+
*/
28+
class QuoteCompiler(directory: AbstractFile) extends Compiler {
29+
import tpd._
30+
31+
/** A GenBCode phase that outputs to a virtual directory */
32+
private class ExprGenBCode extends GenBCode {
33+
override def phaseName = "genBCode"
34+
override def outputDir(implicit ctx: Context) = directory
35+
}
36+
37+
override protected def frontendPhases: List[List[Phase]] =
38+
List(List(new QuotedFrontend(putInClass = true)))
39+
40+
override protected def picklerPhases: List[List[Phase]] =
41+
List(List(new ReifyQuotes))
42+
43+
override protected def backendPhases: List[List[Phase]] =
44+
List(List(new ExprGenBCode))
45+
46+
override def newRun(implicit ctx: Context): ExprRun = {
47+
reset()
48+
new ExprRun(this, ctx.addMode(Mode.ReadPositions))
49+
}
50+
51+
def outputClassName: TypeName = "Quoted".toTypeName
52+
53+
/** Frontend that receives a scala.quoted.Expr or scala.quoted.Type as input */
54+
class QuotedFrontend(putInClass: Boolean) extends FrontEnd {
55+
import tpd._
56+
57+
override def isTyper = false
58+
59+
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
60+
units.map {
61+
case exprUnit: ExprCompilationUnit =>
62+
val tree =
63+
if (putInClass) inClass(exprUnit.expr)
64+
else PickledQuotes.quotedExprToTree(exprUnit.expr)
65+
val source = new SourceFile("", Seq())
66+
CompilationUnit.mkCompilationUnit(source, tree, forceTrees = true)
67+
case typeUnit: TypeCompilationUnit =>
68+
assert(!putInClass)
69+
val tree = PickledQuotes.quotedTypeToTree(typeUnit.tpe)
70+
val source = new SourceFile("", Seq())
71+
CompilationUnit.mkCompilationUnit(source, tree, forceTrees = true)
72+
}
73+
}
74+
75+
/** Places the contents of expr in a compilable tree for a class
76+
* with the following format.
77+
* `package __root__ { class ' { def apply: Any = <expr> } }`
78+
*/
79+
private def inClass(expr: Expr[_])(implicit ctx: Context): Tree = {
80+
val pos = Position(0)
81+
val assocFile = new PlainFile(Path("<quote>"))
82+
83+
val cls = ctx.newCompleteClassSymbol(defn.RootClass, outputClassName, EmptyFlags,
84+
defn.ObjectType :: Nil, newScope, coord = pos, assocFile = assocFile).entered.asClass
85+
cls.enter(ctx.newDefaultConstructor(cls), EmptyScope)
86+
val meth = ctx.newSymbol(cls, nme.apply, Method, ExprType(defn.AnyType), coord = pos).entered
87+
88+
val quoted = PickledQuotes.quotedExprToTree(expr)(ctx.withOwner(meth))
89+
90+
val run = DefDef(meth, quoted)
91+
val classTree = ClassDef(cls, DefDef(cls.primaryConstructor.asTerm), run :: Nil)
92+
PackageDef(ref(defn.RootPackage).asInstanceOf[Ident], classTree :: Nil).withPos(pos)
93+
}
94+
}
95+
96+
class ExprRun(comp: Compiler, ictx: Context) extends Run(comp, ictx) {
97+
def compileExpr(expr: Expr[_]): Unit = {
98+
val units = new ExprCompilationUnit(expr) :: Nil
99+
compileUnits(units)
100+
}
101+
def compileType(tpe: Type[_]): Unit = {
102+
val units = new TypeCompilationUnit(tpe) :: Nil
103+
compileUnits(units)
104+
}
105+
}
106+
107+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package dotty.tools.dotc.quoted
2+
3+
import dotty.tools.dotc.ast.tpd
4+
import dotty.tools.dotc.core.Contexts.Context
5+
import dotty.tools.dotc.core.Phases.Phase
6+
7+
/** Compiler that takes the contents of a quoted expression (or type) and outputs it's tree. */
8+
class QuoteDecompiler(output: tpd.Tree => Context => Unit) extends QuoteCompiler(null) {
9+
override def phases: List[List[Phase]] = List(
10+
List(new QuotedFrontend(putInClass = false)), // Create class from Expr
11+
List(new QuoteTreeOutput(output))
12+
)
13+
14+
class QuoteTreeOutput(output: tpd.Tree => Context => Unit) extends Phase {
15+
override def phaseName: String = "quoteOutput"
16+
override def run(implicit ctx: Context): Unit = output(ctx.compilationUnit.tpdTree)(ctx)
17+
}
18+
}

0 commit comments

Comments
 (0)