Skip to content

Commit b939e8f

Browse files
committed
First untested attempt to create a runtime comp...
First untested attempt to create a runtime compiler. Review by extempore.
1 parent a2e9a1b commit b939e8f

File tree

2 files changed

+76
-20
lines changed

2 files changed

+76
-20
lines changed

src/compiler/scala/reflect/runtime/ToolBoxes.scala

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,67 @@ import scala.tools.nsc.ReflectGlobal
77
import scala.tools.nsc.CompilerCommand
88
import scala.tools.nsc.Global
99
import scala.tools.nsc.typechecker.Modes
10+
import scala.tools.nsc.io.VirtualDirectory
11+
import scala.tools.nsc.interpreter.AbstractFileClassLoader
12+
import reflect.{mirror => rm}
13+
import scala.tools.nsc.util.FreshNameCreator
14+
import scala.reflect.internal.Flags
15+
import scala.tools.nsc.util.NoSourceFile
16+
import java.lang.{Class => jClass}
1017

1118
trait ToolBoxes extends { self: Universe =>
1219

1320
class ToolBox(val reporter: Reporter = new StoreReporter, val options: String = "") {
1421

15-
lazy val compiler: Global = {
22+
class ToolBoxGlobal(settings: scala.tools.nsc.Settings, reporter: scala.tools.nsc.reporters.Reporter)
23+
extends ReflectGlobal(settings, reporter) {
24+
import definitions._
25+
26+
private final val wrapperMethodName = "wrapper"
27+
28+
private def isFree(t: Tree) = t.isInstanceOf[Ident] && t.symbol.isInstanceOf[FreeVar]
29+
30+
def wrapInClass(expr: Tree, fvs: List[Symbol]): ClassDef = {
31+
val clazz = EmptyPackageClass.newAnonymousClass(NoPosition)
32+
clazz setInfo ClassInfoType(List(ObjectClass.tpe), new Scope, clazz)
33+
val meth = clazz.newMethod(NoPosition, wrapperMethodName)
34+
meth setFlag Flags.STATIC
35+
meth setInfo MethodType(meth.owner.newSyntheticValueParams(fvs map (_.tpe)), expr.tpe)
36+
clazz.info.decls enter meth
37+
val methdef = DefDef(meth, expr)
38+
val clazzdef = ClassDef(clazz, NoMods, List(List()), List(List()), List(methdef), NoPosition)
39+
clazzdef
40+
}
41+
42+
def wrapInCompilationUnit(tree: Tree): CompilationUnit = {
43+
val unit = new CompilationUnit(NoSourceFile)
44+
unit.body = tree
45+
unit
46+
}
47+
48+
def compileExpr(expr: Tree, fvs: List[Symbol]): String = {
49+
val cdef = wrapInClass(expr, fvs)
50+
val unit = wrapInCompilationUnit(cdef)
51+
val run = new Run
52+
run.compileUnits(List(unit), run.namerPhase)
53+
cdef.name.toString
54+
}
55+
56+
def runExpr(expr: Tree): Any = {
57+
val fvs = (expr filter isFree map (_.symbol)).distinct
58+
val className = compileExpr(expr, fvs)
59+
val jclazz = jClass.forName(className, true, classLoader)
60+
val jmeth = jclazz.getDeclaredMethods.find(_.getName == wrapperMethodName).get
61+
jmeth.invoke(null, fvs map (sym => sym.asInstanceOf[FreeVar].value.asInstanceOf[AnyRef]): _*)
62+
}
63+
}
64+
65+
lazy val virtualDirectory = new VirtualDirectory("(memory)", None)
66+
67+
lazy val compiler: ToolBoxGlobal = {
1668
val command = new CompilerCommand(options.split(" ").toList, reporter.error(scala.tools.nsc.util.NoPosition, _))
17-
new ReflectGlobal(command.settings, reporter)
69+
command.settings.outputDirs setSingleOutput virtualDirectory
70+
new ToolBoxGlobal(command.settings, reporter)
1871
}
1972

2073
lazy val importer = new compiler.Importer {
@@ -23,20 +76,23 @@ trait ToolBoxes extends { self: Universe =>
2376

2477
lazy val exporter = importer.reverse
2578

26-
def typeCheck(tree: reflect.mirror.Tree, expectedType: reflect.mirror.Type): reflect.mirror.Tree = {
79+
lazy val classLoader = new AbstractFileClassLoader(virtualDirectory, getClass.getClassLoader)
80+
81+
82+
def typeCheck(tree: rm.Tree, expectedType: rm.Type): rm.Tree = {
2783
if (compiler.settings.verbose.value) println("typing "+tree+", pt = "+expectedType)
2884
val run = new compiler.Run
2985
compiler.phase = run.refchecksPhase
3086
val ctree: compiler.Tree = importer.importTree(tree.asInstanceOf[Tree])
3187
val pt: compiler.Type = importer.importType(expectedType.asInstanceOf[Type])
3288
val ttree: compiler.Tree = compiler.typer.typed(ctree, compiler.analyzer.EXPRmode, pt)
33-
exporter.importTree(ttree).asInstanceOf[reflect.mirror.Tree]
89+
exporter.importTree(ttree).asInstanceOf[rm.Tree]
3490
}
3591

36-
def typeCheck(tree: reflect.mirror.Tree): reflect.mirror.Tree =
37-
typeCheck(tree, WildcardType.asInstanceOf[reflect.mirror.Type])
92+
def typeCheck(tree: rm.Tree): rm.Tree =
93+
typeCheck(tree, WildcardType.asInstanceOf[rm.Type])
3894

39-
def showAttributed(tree: reflect.mirror.Tree): String = {
95+
def showAttributed(tree: rm.Tree): String = {
4096
val saved = compiler.settings.printtypes.value
4197
try {
4298
compiler.settings.printtypes.value = true

src/compiler/scala/tools/nsc/Global.scala

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -997,24 +997,24 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
997997
return
998998
}
999999

1000-
val startTime = currentTime
1001-
reporter.reset();
1002-
{
1003-
val first :: rest = sources
1004-
val unit = new CompilationUnit(first)
1005-
addUnit(unit)
1006-
checkDeprecatedSettings(unit)
1007-
1008-
for (source <- rest)
1009-
addUnit(new CompilationUnit(source))
1010-
}
1011-
globalPhase = firstPhase
1000+
compileUnits(sources map (new CompilationUnit(_)), firstPhase)
1001+
}
10121002

1003+
/** Compile list of units, starting with phase `fromPhase`
1004+
*/
1005+
def compileUnits(units: List[CompilationUnit], fromPhase: Phase) {
1006+
units foreach addUnit
10131007
if (opt.profileAll) {
10141008
inform("starting CPU profiling on compilation run")
10151009
profiler.startProfiling()
10161010
}
1017-
while (globalPhase != terminalPhase && !reporter.hasErrors) {
1011+
val startTime = currentTime
1012+
1013+
reporter.reset()
1014+
checkDeprecatedSettings(unitbuf.head)
1015+
globalPhase = firstPhase
1016+
1017+
while (globalPhase != terminalPhase && !reporter.hasErrors) {
10181018
val startTime = currentTime
10191019
phase = globalPhase
10201020

0 commit comments

Comments
 (0)