Runtime evaluation: Difference between revisions
Content added Content deleted
(Added Java implementation) |
|||
Line 615: | Line 615: | ||
=={{header|Java}}== |
|||
You can kind-of do this in Java. The compiler has the relevant APIs, so it is "considered part of your language/library/platform". You have to get a compiler (which may fail), make a pseudo-file-system, compile your class, and make a class loader that will load it. Then you can use regular Java reflection to make an instance and call methods on it. |
|||
Longest "Hello world" program ever?<lang Java>import java.io.ByteArrayOutputStream; |
|||
import java.io.IOException; |
|||
import java.io.OutputStream; |
|||
import java.lang.reflect.InvocationTargetException; |
|||
import java.net.URI; |
|||
import java.util.HashMap; |
|||
import java.util.LinkedList; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import javax.tools.FileObject; |
|||
import javax.tools.ForwardingJavaFileManager; |
|||
import javax.tools.JavaCompiler; |
|||
import javax.tools.JavaFileObject; |
|||
import javax.tools.SimpleJavaFileObject; |
|||
import javax.tools.StandardJavaFileManager; |
|||
import javax.tools.StandardLocation; |
|||
import javax.tools.ToolProvider; |
|||
public class Evaluator{ |
|||
public static void main(String[] args){ |
|||
new Evaluator().eval( |
|||
"SayHello", |
|||
"public class SayHello{public void speak(){System.out.println(\"Hello world\");}}", |
|||
"speak" |
|||
); |
|||
} |
|||
void eval(String className, String classCode, String methodName){ |
|||
Map<String, ByteArrayOutputStream> classCache = new HashMap<>(); |
|||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); |
|||
if ( null == compiler ) |
|||
throw new RuntimeException("Could not get a compiler."); |
|||
StandardJavaFileManager sfm = compiler.getStandardFileManager(null, null, null); |
|||
ForwardingJavaFileManager<StandardJavaFileManager> fjfm = new ForwardingJavaFileManager<StandardJavaFileManager>(sfm){ |
|||
@Override |
|||
public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) |
|||
throws IOException{ |
|||
if (StandardLocation.CLASS_OUTPUT == location && JavaFileObject.Kind.CLASS == kind) |
|||
return new SimpleJavaFileObject(URI.create("mem:///" + className + ".class"), JavaFileObject.Kind.CLASS){ |
|||
@Override |
|||
public OutputStream openOutputStream() |
|||
throws IOException{ |
|||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
|||
classCache.put(className, baos); |
|||
return baos; |
|||
} |
|||
}; |
|||
else |
|||
throw new IllegalArgumentException("Unexpected output file requested: " + location + ", " + className + ", " + kind); |
|||
} |
|||
}; |
|||
List<JavaFileObject> files = new LinkedList<JavaFileObject>(){{ |
|||
add( |
|||
new SimpleJavaFileObject(URI.create("string:///" + className + ".java"), JavaFileObject.Kind.SOURCE){ |
|||
@Override |
|||
public CharSequence getCharContent(boolean ignoreEncodingErrors){ |
|||
return classCode; |
|||
} |
|||
} |
|||
); |
|||
}}; |
|||
// Now we can compile! |
|||
compiler.getTask(null, fjfm, null, null, null, files).call(); |
|||
try{ |
|||
Class<?> clarse = new ClassLoader(){ |
|||
@Override |
|||
public Class<?> findClass(String name){ |
|||
if (! name.startsWith(className)) |
|||
throw new IllegalArgumentException("This class loader is for " + className + " - could not handle \"" + name + '"'); |
|||
byte[] bytes = classCache.get(name).toByteArray(); |
|||
return defineClass(name, bytes, 0, bytes.length); |
|||
} |
|||
}.loadClass(className); |
|||
clarse.getMethod(methodName).invoke(clarse.newInstance()); |
|||
}catch(ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException x){ |
|||
throw new RuntimeException("Run failed: " + x, x); |
|||
} |
|||
} |
|||
}</lang> |
|||
{{Out}} |
|||
<pre>Hello world</pre> |
|||
If you have a JRE and not a JDK, there is no compiler, so this doesn't work.<pre>Exception in thread "main" java.lang.RuntimeException: Could not get a compiler. |
|||
at Evaluator.eval(Evaluator.java:33) |
|||
at Evaluator.main(Evaluator.java:21)</pre> |
|||
=={{header|Lasso}}== |
=={{header|Lasso}}== |
||
"Sourcefile" when executed has access to all variables and other data that would be available in scope to an included file. |
"Sourcefile" when executed has access to all variables and other data that would be available in scope to an included file. |