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

A GenBCode phase that uses virtualDirectory for its output

private class Request

One line of code submitted by the user for interpretation

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

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

val classLoader : ClassLoader

class loader used to load compiled code

class loader used to load compiled code

val compilerClasspath : Seq [ URL ]

the compiler's classpath, as URL's

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

next internal variable number to use

private var nextLineNo : Int

next line number to use

next line number to use

private var nextVarNameNo : Int

next result variable number to use

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

the previous requests this interpreter has processed

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

whether to print out result lines

whether to print out result lines

val virtualDirectory : VirtualDirectory | PlainDirectory

directory to save .class files to

directory to save .class files to

override def beQuietDuring ( operation: => T ) : T

Temporarily be quiet

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... [Int] [Int]

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

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.

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.

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

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 ava...

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

Check if a name looks like it was generated by newVarName

override def lastOutput ( ) : Seq [ String ]

Gets the last output not printed immediately

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

allocate a fresh internal variable name

private def newLineName : String

allocate a fresh line name

allocate a fresh line name

private def newReporter : ConsoleReporter
private def newVarName : String

allocate a fresh variable name

allocate a fresh variable name

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

next internal variable number to use

next internal variable number to use

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

next line number to use

next line number to use

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

next result variable number to use

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.

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.

Phases of this compiler use REPLGenBCode instead of GenBCode.

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

whether to print out result lines

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

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

Truncate a string if it is longer than settings.maxPrintString