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