Dotty Documentation


class CompilingInterpreter
extends Compiler with Interpreter

An interpreter for Scala code which is based on the dotc compiler.

The overall approach is based on compiling the requested code and then using a Java classloader and Java reflection to run the code and access its results.

In more detail, a single compiler instance is used to accumulate all successfully compiled or interpreted Scala code. To "interpret" a line of code, the compiler generates a fresh object that includes the line of code and which has public definition(s) to export all variables defined by that code. To extract the result of an interpreted line to show the user, a second "result object" is created which imports the variables exported by the above object and then exports a single definition named "result". To accommodate user expressions that read from variables or methods defined in previous statements, "import" statements are used.

This interpreter shares the strengths and weaknesses of using the full compiler-to-Java. The main strength is that interpreted code behaves exactly as does compiled code, including running at full speed. The main weakness is that redefining classes and methods is not handled properly, because rebinding at the Java level is technically difficult.

[-] Constructors

CompilingInterpreter ( out: PrintWriter , ictx: Context , parentClassLoader: Option [ ClassLoader ] )

[-] Members

[+] private class REPLGenBCode

A GenBCode phase that uses virtualDirectory for its output

[+] private class Request

One line of code submitted by the user for interpretation

[+] private trait StatementInfo

Trait collecting info about one of the statements of an interpreter request

[+] val classLoader : ClassLoader

class loader used to load compiled code

[+] val compilerClasspath : Seq [ URL ]

the compiler's classpath, as URL's

[+] private var delayOutput : Boolean
[+] private val ictx : Context
[+] private var nextInternalVarNo : Int

next internal variable number to use

[+] private var nextLineNo : Int

next line number to use

[+] private var nextVarNameNo : Int

next result variable number to use

[+] private val out : PrintWriter
[+] private val parentClassLoader : Option [ ClassLoader ]
[+] private val prevRequests : ArrayBuffer [ Request ]

the previous requests this interpreter has processed

[+] val previousOutput : ListBuffer [ String ]
[+] private var printResults : Boolean

whether to print out result lines

[+] val virtualDirectory : AbstractFile

directory to save .class files to

[+] override def beQuietDuring ( operation: => T ) : T

Temporarily be quiet

[+] override def bind ( id: String , boundType: String , value: AnyRef ) ( implicit ctx: Context ) : Result

This bind is implemented by creating an object with a set method and a field value. The value is then set via Java reflection.

Example: We want to bind a value List(1,2,3) to identifier list from sbt. The bind method accomplishes this by creating the following: {{{ object ContainerObjectWithUniqueID { var value: List[Int] = _ def set(x: Any) = value = x.asInstanceOf[List[Int]] } val list = ContainerObjectWithUniqueID.value }}}

Between the object being created and the value being assigned, the value inside the object is set via reflection.

[+] private def clean ( str: String ) ( implicit ctx: Context ) : String

Clean up a string for output

[+] def compileSources ( sources: List [ SourceFile ] ) ( implicit ctx: Context ) : Context

Compile a SourceFile. Returns the root context of the run that compiled the file.

[+] def compileString ( code: String ) ( implicit ctx: Context ) : Boolean

Compile a string. Returns true if there are no compilation errors, or false otherwise.

[+] private def currentLineName : String
[+] override def delayOutputDuring ( operation: => T ) : T

Suppresses output and saves it for lastOutput to collect

[+] private def delayOutput_= ( x$1: Boolean ) : Unit
[+] override def interpret ( line: String ) ( implicit ctx: Context ) : Result

Interpret one line of input. All feedback, including parse errors and evaluation results, are printed via the context's reporter. Values defined are available for future interpreted strings.

[+] private def isGeneratedVarName ( name: String ) : Boolean

Check if a name looks like it was generated by newVarName

[+] override def lastOutput ( ) : Seq [ String ]

Gets the last output not printed immediately

[+] private def loadAndSetValue ( objectName: String , value: AnyRef ) : Boolean
[+] private def newInternalVarName ( ) : String

allocate a fresh internal variable name

[+] private def newLineName : String

allocate a fresh line name

[+] private def newReporter : ConsoleReporter
[+] private def newVarName : String

allocate a fresh variable name

[+] private def nextInternalVarNo_= ( x$1: Int ) : Unit

next internal variable number to use

[+] private def nextLineNo_= ( x$1: Int ) : Unit

next line number to use

[+] private def nextVarNameNo_= ( x$1: Int ) : Unit

next result variable number to use

[+] private def parse ( line: String ) ( implicit ctx: Context ) : Option [ List [ Tree ] ]

Parse a line into a sequence of trees. Returns None if the input is incomplete.

[+] override def phases : List [ List [ Phase ] ]

Phases of this compiler use REPLGenBCode instead of GenBCode.

[+] private def printResults_= ( x$1: Boolean ) : Unit

whether to print out result lines

[+] private def stringFrom ( writer: PrintWriter => Unit ) : String

generate a string using a routine that wants to write on a stream

[+] private def truncPrintString ( str: String ) ( implicit ctx: Context ) : String

Truncate a string if it is longer than settings.maxPrintString