Skip to content

Implement decompiler on Tasty #4579

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 31, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import dotty.tools.dotc.core.Contexts._
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.core.tasty.TastyPrinter
import dotty.tools.dotc.printing.DecompilerPrinter
import dotty.tools.dotc.tastyreflect.TastyImpl
import dotty.tools.io.{File, Path}

/** Phase that prints the trees in all loaded compilation units.
Expand Down Expand Up @@ -36,15 +37,11 @@ class DecompilationPrinter extends Phase {

private def printToOutput(out: PrintStream)(implicit ctx: Context): Unit = {
val unit = ctx.compilationUnit
val pageWidth = ctx.settings.pageWidth.value
val printLines = ctx.settings.printLines.value

if (ctx.settings.printTasty.value) {
new TastyPrinter(unit.pickled.head._2).printContents()
} else {
out.println(s"/** Decompiled from $unit */")
val printer = new DecompilerPrinter(ctx)
out.println(printer.toText(unit.tpdTree).mkString(pageWidth, printLines))
out.print(TastyImpl.showSourceCode.showTree(unit.tpdTree)(ctx))
}
}
}
9 changes: 3 additions & 6 deletions compiler/src/dotty/tools/dotc/quoted/QuoteDriver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import dotty.tools.dotc.Driver
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.io.{AbstractFile, Directory, PlainDirectory, VirtualDirectory}
import dotty.tools.repl.AbstractFileClassLoader
import dotty.tools.dotc.printing.DecompilerPrinter

import scala.quoted.{Expr, Type}

import java.net.URLClassLoader

import Toolbox.{Settings, Run, Show}
import Toolbox.{Run, Settings, Show}
import dotty.tools.dotc.tastyreflect.TastyImpl

class QuoteDriver extends Driver {
import tpd._
Expand Down Expand Up @@ -42,10 +41,8 @@ class QuoteDriver extends Driver {

def show(expr: Expr[_], settings: Settings[Show]): String = {
def show(tree: Tree, ctx: Context): String = {
val printer = new DecompilerPrinter(ctx)
val pageWidth = ctx.settings.pageWidth.value(ctx)
val tree1 = if (settings.rawTree) tree else (new TreeCleaner).transform(tree)(ctx)
printer.toText(tree1).mkString(pageWidth, false)
TastyImpl.showSourceCode.showTree(tree1)(ctx)
}
withTree(expr, show, settings)
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/tastyreflect/FlagSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class FlagSet(flags: Flags.FlagSet) extends scala.tasty.FlagSet {
def isScala2X: Boolean = flags.is(Scala2x)
def isDefaultParameterized: Boolean = flags.is(DefaultParameterized)
def isStable: Boolean = flags.is(Stable)
def isParam: Boolean = flags.is(Param)
def isParamAccessor: Boolean = flags.is(ParamAccessor)

override def toString: String = {
val flags = List.newBuilder[String]
Expand Down Expand Up @@ -60,6 +62,8 @@ class FlagSet(flags: Flags.FlagSet) extends scala.tasty.FlagSet {
if (isScala2X) flags += "scala2x"
if (isDefaultParameterized) flags += "defaultParameterized"
if (isStable) flags += "stable"
if (isParam) flags += "param"
if (isParamAccessor) flags += "paramAccessor"
flags.result().mkString("<", ",", ">")
}

Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/tastyreflect/FromSymbol.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ object FromSymbol {
def packageDef(sym: Symbol)(implicit ctx: Context): PackageDefinition = PackageDefinitionImpl(sym)

def classDef(cls: ClassSymbol)(implicit ctx: Context): tpd.Tree = {
val constr = tpd.DefDef(cls.unforcedDecls.find(_.isPrimaryConstructor).asTerm)
val constrSym = cls.unforcedDecls.find(_.isPrimaryConstructor)
if (!constrSym.exists) return tpd.EmptyTree
val constr = tpd.DefDef(constrSym.asTerm)
val body = cls.unforcedDecls.filter(!_.isPrimaryConstructor).map(s => definition(s))
val superArgs = Nil // TODO
tpd.ClassDef(cls, constr, body, superArgs)
Expand Down
15 changes: 11 additions & 4 deletions compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import dotty.tools.dotc.reporting.Reporter
import dotty.tools.dotc.reporting.diagnostic.MessageContainer
import dotty.tools.dotc.util.SourcePosition

import scala.quoted
import scala.{quoted, tasty}
import scala.reflect.ClassTag
import scala.tasty.util.{Show, ShowExtractors}
import scala.tasty.util.{Show, ShowExtractors, ShowSourceCode}

object TastyImpl extends scala.tasty.Tasty {

Expand All @@ -33,8 +33,7 @@ object TastyImpl extends scala.tasty.Tasty {

def showExtractors: Show[this.type] = new ShowExtractors(this)

// TODO
// def showSourceCode: Show[this.type] = ???
def showSourceCode: Show[this.type] = new ShowSourceCode(this)

// ===== Contexts =================================================

Expand Down Expand Up @@ -129,10 +128,18 @@ object TastyImpl extends scala.tasty.Tasty {

type Definition = tpd.Tree

object Definition extends DefinitionExtractor {
def unapply(x: Definition)(implicit ctx: Context): Boolean =
x.isInstanceOf[Trees.MemberDef[_]]
}

def DefinitionDeco(x: Definition): AbstractDefinition = new AbstractDefinition {

def owner(implicit ctx: Context): Definition = FromSymbol.definition(x.symbol.owner)

def flags(implicit ctx: Contexts.Context): FlagSet =
new FlagSet(x.symbol.flags)

def mods(implicit ctx: Context): List[Modifier] = {
val privateWithin = x.symbol.privateWithin
val isProtected = x.symbol.is(core.Flags.Protected)
Expand Down
3 changes: 2 additions & 1 deletion compiler/test/dotty/tools/dotc/FromTastyTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ class FromTastyTests extends ParallelTesting {
"t3612.scala",
),
recompilationBlacklist = Set(
"simpleCaseObject"
"simpleCaseObject",
"annot-bootstrap.scala",
)
).checkCompile()
}
Expand Down
2 changes: 2 additions & 0 deletions library/src/scala/tasty/FlagSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ trait FlagSet {
def isScala2X: Boolean // Imported from Scala2.x
def isDefaultParameterized: Boolean // Method with default parameters
def isStable: Boolean // Method that is assumed to be stable
def isParam: Boolean
def isParamAccessor: Boolean
}
9 changes: 7 additions & 2 deletions library/src/scala/tasty/Tasty.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ abstract class Tasty { tasty =>

def showExtractors: Show[tasty.type]

// TODO
// def showSourceCode: Show[tasty.type]
def showSourceCode: Show[tasty.type]

// ===== Contexts =================================================

Expand Down Expand Up @@ -108,9 +107,15 @@ abstract class Tasty { tasty =>

type Definition <: Statement

val Definition: DefinitionExtractor
abstract class DefinitionExtractor {
def unapply(x: Definition)(implicit ctx: Context): Boolean
}

implicit def definitionClassTag: ClassTag[Definition]

trait AbstractDefinition {
def flags(implicit ctx: Context): FlagSet
def mods(implicit ctx: Context): List[Modifier]
def owner(implicit ctx: Context): Definition
def localContext(implicit ctx: Context): Context
Expand Down
Loading