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.