Skip to content

Instantly share code, notes, and snippets.

@ymnk
Created September 22, 2008 20:03
Show Gist options
  • Save ymnk/12135 to your computer and use it in GitHub Desktop.
Save ymnk/12135 to your computer and use it in GitHub Desktop.
import scala.tools.nsc.{Interpreter, Properties, Settings}
import scala.util.matching.Regex
import java.io.ByteArrayOutputStream
import Thread.currentThread;
/**
* 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 CompileAndLoad {
/**
* "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, Object), String] = {
val originalClassLoader = currentThread.getContextClassLoader
val interpreter = new Interpreter(new Settings)
interpreter.setContextClassLoader
try{
val objName = "FOO"
val mName = "value"
val _code=String.format("object %s { val %s = { %s } }",
objName, mName, code)
val bao=new ByteArrayOutputStream
if(Console.withOut(bao){ interpreter.compileString(_code) }){ // compile
// Retrieve the value bound to "FOO.value"
val obj = Class.forName(objName,
true,
currentThread.getContextClassLoader)
var m = obj.getDeclaredMethods.toList.find(_.getName==mName).get
val value = m.invoke(obj)
// Retrieve the type for "code"
val b = new java.io.ByteArrayOutputStream
Console.withOut(b) {
interpreter.interpret(code)
}
// The pattern for "res0: (String) => (String) = <function>\n"
val pattern = "^\\w+:\\s(.*)\\s=\\s.*\\r?\\n".r
val typ = b.toString match { case pattern(typ) => typ }
Left((typ, value))
}
else{
//bao.close; Right(bao.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