comparison 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
comparison
equal deleted inserted replaced
647:8e8c30b72e9b 648:e387e4021afe
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 javax.tools.FileObject;
10 import javax.tools.JavaFileObject;
11 import javax.tools.SimpleJavaFileObject;
12 import javax.tools.JavaCompiler;
13 import javax.tools.ToolProvider;
14 import javax.tools.JavaFileManager;
15 import javax.tools.StandardJavaFileManager;
16 import javax.tools.ForwardingJavaFileManager;
17
18
19 public final class LuanJavaCompiler {
20 private LuanJavaCompiler() {} // never
21
22 public static Class compile(final String className,final String sourceName,final String code) throws ClassNotFoundException {
23 final int len = sourceName.length();
24 StringBuilder sb = new StringBuilder(sourceName);
25 for( int i=0; i<len; i++ )
26 sb.setCharAt(i,'$');
27 JavaFileObject sourceFile = new SimpleJavaFileObject(URI.create(sb.toString()),JavaFileObject.Kind.SOURCE) {
28 @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) {
29 return code;
30 }
31 @Override public String getName() {
32 return sourceName;
33 }
34 @Override public boolean isNameCompatible(String simpleName,JavaFileObject.Kind kind) {
35 return true;
36 }
37 };
38 ByteArrayOutputStream baos = new ByteArrayOutputStream();
39 JavaFileObject classFile = new SimpleJavaFileObject(URI.create("whatever"),JavaFileObject.Kind.CLASS) {
40 @Override public OutputStream openOutputStream() {
41 return baos;
42 }
43 };
44 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
45 StandardJavaFileManager sjfm = compiler.getStandardFileManager(null,null,null);
46 ForwardingJavaFileManager fjfm = new ForwardingJavaFileManager(sjfm) {
47 @Override public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
48 return classFile;
49 }
50 };
51 StringWriter out = new StringWriter();
52 boolean b = compiler.getTask(out, fjfm, null, null, null, Collections.singletonList(sourceFile)).call();
53 if( !b )
54 throw new RuntimeException("\n"+out);
55 byte[] byteCode = baos.toByteArray();
56 int max = byteCode.length-len-3;
57 outer:
58 for( int i=0; true; i++ ) {
59 if( i > max )
60 throw new RuntimeException();
61 if( byteCode[i]==1 && byteCode[i+1]*256 + byteCode[i+2] == len ) {
62 for( int j=i+3; j<i+3+len; j++ ) {
63 if( byteCode[j] != '$' )
64 continue outer;
65 }
66 System.arraycopy(sourceName.getBytes(),0,byteCode,i+3,len);
67 break;
68 }
69 }
70 ClassLoader cl = new ClassLoader() {
71 @Override protected Class<?> findClass(String name) throws ClassNotFoundException {
72 if( name.equals(className) ) {
73 return defineClass(name, byteCode, 0, byteCode.length);
74 }
75 return super.findClass(name);
76 }
77 };
78 return cl.loadClass(className);
79 }
80 }