Runtime evaluation: Difference between revisions

Added Java implementation
(Added Java implementation)
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}}==
"Sourcefile" when executed has access to all variables and other data that would be available in scope to an included file.
Anonymous user