Mercurial Hosting > luan
view src/luan/impl/LuanJavaCompiler.java @ 1392:002152af497a
hosted postgres
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 06 Sep 2019 00:19:47 -0600 |
parents | 1a68fc55a80c |
children |
line wrap: on
line source
package luan.impl; import java.io.OutputStream; import java.io.ByteArrayOutputStream; import java.io.StringWriter; import java.io.IOException; import java.net.URI; import java.util.Collections; import java.util.Map; import java.util.HashMap; import javax.tools.FileObject; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import javax.tools.JavaFileManager; import javax.tools.StandardJavaFileManager; import javax.tools.ForwardingJavaFileManager; public final class LuanJavaCompiler { private LuanJavaCompiler() {} // never private static class MyJavaFileObject extends SimpleJavaFileObject { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); MyJavaFileObject() { super(URI.create("whatever"),JavaFileObject.Kind.CLASS); } @Override public OutputStream openOutputStream() { return baos; } byte[] byteCode(String sourceName) { byte[] byteCode = baos.toByteArray(); final int len = sourceName.length(); int max = byteCode.length-len-3; outer: for( int i=0; true; i++ ) { if( i > max ) throw new RuntimeException("len="+len); if( byteCode[i]==1 && (byteCode[i+1] << 8 | 0xFF & byteCode[i+2]) == len ) { for( int j=i+3; j<i+3+len; j++ ) { if( byteCode[j] != '$' ) continue outer; } System.arraycopy(sourceName.getBytes(),0,byteCode,i+3,len); break; } } return byteCode; } } public static Class compile(final String className,final String sourceName,final String code) throws ClassNotFoundException { final int len = sourceName.length(); StringBuilder sb = new StringBuilder(sourceName); for( int i=0; i<len; i++ ) sb.setCharAt(i,'$'); JavaFileObject sourceFile = new SimpleJavaFileObject(URI.create(sb.toString()),JavaFileObject.Kind.SOURCE) { @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return code; } @Override public String getName() { return sourceName; } @Override public boolean isNameCompatible(String simpleName,JavaFileObject.Kind kind) { return true; } }; final Map<String,MyJavaFileObject> map = new HashMap<String,MyJavaFileObject>(); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager sjfm = compiler.getStandardFileManager(null,null,null); ForwardingJavaFileManager fjfm = new ForwardingJavaFileManager(sjfm) { @Override public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { if( map.containsKey(className) ) throw new RuntimeException(className); MyJavaFileObject classFile = new MyJavaFileObject(); map.put(className,classFile); return classFile; } }; StringWriter out = new StringWriter(); boolean b = compiler.getTask(out, fjfm, null, null, null, Collections.singletonList(sourceFile)).call(); if( !b ) throw new RuntimeException("\n"+out+"\ncode:\n"+code+"\n"); ClassLoader cl = new ClassLoader() { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { MyJavaFileObject jfo = map.get(name); if( jfo != null ) { byte[] byteCode = jfo.byteCode(sourceName); return defineClass(name, byteCode, 0, byteCode.length); } return super.findClass(name); } }; return cl.loadClass(className); } }