Created
September 24, 2008 08:21
-
-
Save ymnk/12506 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.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