Skip to content

Instantly share code, notes, and snippets.

@ymnk
Created September 24, 2008 08:21
Show Gist options
  • Save ymnk/12506 to your computer and use it in GitHub Desktop.
Save ymnk/12506 to your computer and use it in GitHub Desktop.
import scala.tools.nsc.{Interpreter, Properties, Settings}
import scala.tools.nsc.{InterpreterResults=>IR}
import java.io.ByteArrayOutputStream
import java.lang.reflect.Method
import Thread.currentThread;
import scala.util.matching.Regex
/**
* This program demonstrates the dynamic compilation and loading to JVM.
*
* A string will be read from stdin, and compiled and loaded dynamically.
* If the result is the function of String => _, "Hello" will be applied to it.
*/
object CompileAndLoad2 {
/**
* "code" will be compiled and loaded.
* If there is no compilation error, its type as String and evaluated
* object will be returned in Left.
* If errors occur, Right will be returned with error messages.
*/
def compileAndLoad(code:String):Either[(String, Any), String] = {
val originalClassLoader = currentThread.getContextClassLoader()
val interpreter = new Interpreter(new Settings)
interpreter.setContextClassLoader()
try{
val b = new java.io.ByteArrayOutputStream
Console.withOut(b) { interpreter.interpret(code) } match {
case IR.Success => {
// The pattern for "res0: (String) => (String) = <function>\n"
val pattern="^res(\\w+):\\s(.*)\\s=\\s.*\\r?\\n".r
val (n, typ)=b.toString match {
case pattern(n,typ) => (n, typ)
case _ => return Right("not compiled to value")
}
// The class "line0$object$$iw$$iw$" will have the method "res0",
// which will return the value bound to "res0".
val obj = Class.forName("line"+(n)+"$object$$iw$$iw$",
true,
currentThread.getContextClassLoader)
var resn =
obj.getDeclaredMethods.toList.find(_.getName=="res"+n).get
Left((typ, resn.invoke(obj.newInstance)))
}
case IR.Incomplete => {
Right("incomplete code")
}
case IR.Error => {
Right(b.toString)
//Right("compile error")
}
}
}
finally{
currentThread.setContextClassLoader(originalClassLoader)
interpreter.close
}
}
def main(arg:Array[String]){
// This program expects Scala 2.7.2 environment.
//if(!Properties.versionString.startsWith("version 2.7.2")){
// exit
//}
val l = scala.Console.readLine
compileAndLoad(l) match {
// compilation error
case Right(err) => println(err)
// Because of the Type Erasure, type parameters are unknown.
// So, we will check its type with if(type.statsWith("(String)"))
case Left((typ, f:Function1[_,_])) if (typ.startsWith("(String)")) => {
val value = "Hello"
println(f.asInstanceOf[String => _](value))
}
case Left((_, _)) => { println("unexpected type") }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment