comparison 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
comparison
equal deleted inserted replaced
774:3e30cf310e56 775:1a68fc55a80c
1 package luan.impl;
2
3 import java.io.OutputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.StringWriter;
6 import java.io.IOException;
7 import java.net.URI;
8 import java.util.Collections;
9 import java.util.Map;
10 import java.util.HashMap;
11 import javax.tools.FileObject;
12 import javax.tools.JavaFileObject;
13 import javax.tools.SimpleJavaFileObject;
14 import javax.tools.JavaCompiler;
15 import javax.tools.ToolProvider;
16 import javax.tools.JavaFileManager;
17 import javax.tools.StandardJavaFileManager;
18 import javax.tools.ForwardingJavaFileManager;
19
20
21 public final class LuanJavaCompiler {
22 private LuanJavaCompiler() {} // never
23
24 private static class MyJavaFileObject extends SimpleJavaFileObject {
25 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
26
27 MyJavaFileObject() {
28 super(URI.create("whatever"),JavaFileObject.Kind.CLASS);
29 }
30
31 @Override public OutputStream openOutputStream() {
32 return baos;
33 }
34
35 byte[] byteCode(String sourceName) {
36 byte[] byteCode = baos.toByteArray();
37 final int len = sourceName.length();
38 int max = byteCode.length-len-3;
39 outer:
40 for( int i=0; true; i++ ) {
41 if( i > max )
42 throw new RuntimeException("len="+len);
43 if( byteCode[i]==1 && (byteCode[i+1] << 8 | 0xFF & byteCode[i+2]) == len ) {
44 for( int j=i+3; j<i+3+len; j++ ) {
45 if( byteCode[j] != '$' )
46 continue outer;
47 }
48 System.arraycopy(sourceName.getBytes(),0,byteCode,i+3,len);
49 break;
50 }
51 }
52 return byteCode;
53 }
54 }
55
56 public static Class compile(final String className,final String sourceName,final String code) throws ClassNotFoundException {
57 final int len = sourceName.length();
58 StringBuilder sb = new StringBuilder(sourceName);
59 for( int i=0; i<len; i++ )
60 sb.setCharAt(i,'$');
61 JavaFileObject sourceFile = new SimpleJavaFileObject(URI.create(sb.toString()),JavaFileObject.Kind.SOURCE) {
62 @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) {
63 return code;
64 }
65 @Override public String getName() {
66 return sourceName;
67 }
68 @Override public boolean isNameCompatible(String simpleName,JavaFileObject.Kind kind) {
69 return true;
70 }
71 };
72 final Map<String,MyJavaFileObject> map = new HashMap<String,MyJavaFileObject>();
73 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
74 StandardJavaFileManager sjfm = compiler.getStandardFileManager(null,null,null);
75 ForwardingJavaFileManager fjfm = new ForwardingJavaFileManager(sjfm) {
76 @Override public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
77 if( map.containsKey(className) )
78 throw new RuntimeException(className);
79 MyJavaFileObject classFile = new MyJavaFileObject();
80 map.put(className,classFile);
81 return classFile;
82 }
83 };
84 StringWriter out = new StringWriter();
85 boolean b = compiler.getTask(out, fjfm, null, null, null, Collections.singletonList(sourceFile)).call();
86 if( !b )
87 throw new RuntimeException("\n"+out+"\ncode:\n"+code+"\n");
88 ClassLoader cl = new ClassLoader() {
89 @Override protected Class<?> findClass(String name) throws ClassNotFoundException {
90 MyJavaFileObject jfo = map.get(name);
91 if( jfo != null ) {
92 byte[] byteCode = jfo.byteCode(sourceName);
93 return defineClass(name, byteCode, 0, byteCode.length);
94 }
95 return super.findClass(name);
96 }
97 };
98 return cl.loadClass(className);
99 }
100 }