Mercurial Hosting > luan
diff src/luan/impl/LuanJavaCompiler.java @ 775:1a68fc55a80c
simplify dir structure
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 26 Aug 2016 14:36:40 -0600 |
parents | core/src/luan/impl/LuanJavaCompiler.java@41f8fdbc3a0a |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/impl/LuanJavaCompiler.java Fri Aug 26 14:36:40 2016 -0600 @@ -0,0 +1,100 @@ +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); + } +}