Created
September 22, 2008 20:03
-
-
Save ymnk/12135 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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