diff core/src/luan/impl/LuanJavaCompiler.java @ 648:e387e4021afe

start compiler with len operator
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 30 Mar 2016 19:40:48 -0600
parents
children d658eab7bf4c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/luan/impl/LuanJavaCompiler.java	Wed Mar 30 19:40:48 2016 -0600
@@ -0,0 +1,80 @@
+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 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
+
+	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;
+			}
+		};
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		JavaFileObject classFile = new SimpleJavaFileObject(URI.create("whatever"),JavaFileObject.Kind.CLASS) {
+			@Override public OutputStream openOutputStream() {
+				return baos;
+			}
+		};
+		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 {
+				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);
+		byte[] byteCode = baos.toByteArray();
+		int max = byteCode.length-len-3;
+		outer:
+		for( int i=0; true; i++ ) {
+			if( i > max )
+				throw new RuntimeException();
+			if( byteCode[i]==1 && byteCode[i+1]*256 + 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;
+			}
+		}
+		ClassLoader cl = new ClassLoader() {
+			@Override protected Class<?> findClass(String name) throws ClassNotFoundException {
+				if( name.equals(className) ) {
+					return defineClass(name, byteCode, 0, byteCode.length);
+				}
+				return super.findClass(name);
+			}
+		};
+		return cl.loadClass(className);
+	}
+}