Mercurial Hosting > luan
changeset 648:e387e4021afe
start compiler with len operator
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 30 Mar 2016 19:40:48 -0600 |
parents | 8e8c30b72e9b |
children | 37f0cf43f191 |
files | core/src/luan/impl/$Luan.java core/src/luan/impl/Expressions.java core/src/luan/impl/LuanJavaCompiler.java core/src/luan/impl/LuanParser.java core/src/luan/modules/mmake.luan |
diffstat | 5 files changed, 172 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/$Luan.java Wed Mar 30 19:40:48 2016 -0600 @@ -0,0 +1,46 @@ +package luan.impl; + +import java.util.List; +import java.util.ArrayList; +import luan.Luan; +import luan.LuanTable; +import luan.LuanException; + + +public final class $Luan { + private $Luan() {} // never + + + private static List<Expressions> listExpressions = new ArrayList<Expressions>(); + + static int addExpressions(Expressions exp) { + int i = listExpressions.size(); + listExpressions.add(exp); + return i; + } + + public static Expressions getExpressions(int i) { + return listExpressions.get(i); + } + + + public static Object first(Object obj) { + return Luan.first(obj); + } + + public static int len(LuanStateImpl luan,Object o) throws LuanException { + if( o instanceof String ) { + String s = (String)o; + return s.length(); + } + if( o instanceof byte[] ) { + byte[] a = (byte[])o; + return a.length; + } + if( o instanceof LuanTable ) { + LuanTable t = (LuanTable)o; + return t.length(luan); + } + throw new LuanException( "attempt to get length of a " + Luan.type(o) + " value" ); + } +}
--- a/core/src/luan/impl/Expressions.java Tue Mar 29 20:39:14 2016 -0600 +++ b/core/src/luan/impl/Expressions.java Wed Mar 30 19:40:48 2016 -0600 @@ -3,6 +3,6 @@ import luan.LuanException; -interface Expressions extends Code { +public interface Expressions extends Code { public Object eval(LuanStateImpl luan) throws LuanException; }
--- /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); + } +}
--- a/core/src/luan/impl/LuanParser.java Tue Mar 29 20:39:14 2016 -0600 +++ b/core/src/luan/impl/LuanParser.java Wed Mar 30 19:40:48 2016 -0600 @@ -661,8 +661,10 @@ parser.begin(); if( parser.match('#') ) { Spaces(in); - Expressions exp = UnaryExpr(in); - return parser.success( new LenExpr( required(expr(exp)) ) ); + Expressions exp = required(UnaryExpr(in)); + String code = "$Luan.len($luan," + expressionsToExprString(exp) + ")"; + exp = stringToExpressions(code); + return parser.success(exp); } if( Minus() ) { Spaces(in); @@ -1347,4 +1349,43 @@ return parser.success(); } + + + + private static String expressionsToExprString(Expressions exp) { + int i = $Luan.addExpressions(exp); + String s = "$Luan.getExpressions(" + i + ").eval($luan)"; + if( !(exp instanceof Expr) ) + s = "$Luan.first(" + s + ")"; + return s; + } + + private static int classCounter = 0; + + private static Expressions stringToExpressions(String code) { + String className = "EXP" + ++classCounter; + String classCode = "" + +"package luan.impl;\n" +// +"import luan.impl.$Luan;\n" +// +"import luan.impl.Expressions;\n" + +"import luan.LuanException;\n" + +"\n" + +"public class " + className +" implements Expressions {\n" + +" @Override public Object eval(LuanStateImpl $luan) throws LuanException {\n" + +" return " + code + ";\n" + +" }\n" + +"}\n" + ; + try { + Class cls = LuanJavaCompiler.compile("luan.impl."+className,code,classCode); + return (Expressions)cls.newInstance(); + } catch(ClassNotFoundException e) { + throw new RuntimeException(e); + } catch(InstantiationException e) { + throw new RuntimeException(e); + } catch(IllegalAccessException e) { + throw new RuntimeException(e); + } + } + }
--- a/core/src/luan/modules/mmake.luan Tue Mar 29 20:39:14 2016 -0600 +++ b/core/src/luan/modules/mmake.luan Wed Mar 30 19:40:48 2016 -0600 @@ -17,7 +17,7 @@ .SUFFIXES: .java .class .java.class: - <%=compiler%> $< + <%=compiler%> '$<' all: <% end @@ -41,6 +41,7 @@ local out = dir.child("Makefile").text_writer() out.write( header() ) for _, s in ipairs(javas) do + s = String.gsub(s,[[\$]],[[\$\$]]) out.write( "\\\n\t\t", s , ".class" ) end for _, s in ipairs(dirs) do