Mercurial Hosting > luan
changeset 167:4c0131c2b650
merge luan/lib into modules
git-svn-id: https://luan-java.googlecode.com/svn/trunk@168 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Sun, 22 Jun 2014 04:28:32 +0000 |
parents | 4eaee12f6c65 |
children | ebe9db183eb7 |
files | src/luan/Luan.java src/luan/LuanState.java src/luan/init.luan src/luan/lib/BasicLib.java src/luan/lib/BinaryLib.java src/luan/lib/HtmlLib.java src/luan/lib/HttpLib.java src/luan/lib/IoLib.java src/luan/lib/JavaLib.java src/luan/lib/MathLib.java src/luan/lib/PackageLib.java src/luan/lib/PickleClient.java src/luan/lib/PickleCon.java src/luan/lib/PickleServer.java src/luan/lib/StringLib.java src/luan/lib/TableLib.java src/luan/lib/ThreadLib.java src/luan/lib/Utils.java src/luan/lib/init.luan src/luan/modules/BasicLib.java src/luan/modules/BinaryLib.java src/luan/modules/HtmlLib.java src/luan/modules/HttpLib.java src/luan/modules/IoLib.java src/luan/modules/JavaLib.java src/luan/modules/MathLib.java src/luan/modules/PackageLib.java src/luan/modules/PickleClient.java src/luan/modules/PickleCon.java src/luan/modules/PickleServer.java src/luan/modules/StringLib.java src/luan/modules/TableLib.java src/luan/modules/ThreadLib.java src/luan/modules/Utils.java |
diffstat | 34 files changed, 2861 insertions(+), 2870 deletions(-) [+] |
line wrap: on
line diff
--- a/src/luan/Luan.java Sun Jun 22 04:17:38 2014 +0000 +++ b/src/luan/Luan.java Sun Jun 22 04:28:32 2014 +0000 @@ -1,6 +1,6 @@ package luan; -import luan.lib.BasicLib; +import luan.modules.BasicLib; public final class Luan {
--- a/src/luan/LuanState.java Sun Jun 22 04:17:38 2014 +0000 +++ b/src/luan/LuanState.java Sun Jun 22 04:28:32 2014 +0000 @@ -7,17 +7,8 @@ import java.util.Map; import java.util.LinkedHashMap; import luan.impl.LuanCompiler; -import luan.lib.BasicLib; -import luan.lib.PackageLib; -import luan.lib.JavaLib; -import luan.lib.MathLib; -import luan.lib.StringLib; -import luan.lib.TableLib; -import luan.lib.HtmlLib; -import luan.lib.BinaryLib; -import luan.lib.IoLib; -import luan.lib.ThreadLib; -import luan.lib.HttpLib; +import luan.modules.BasicLib; +import luan.modules.PackageLib; public abstract class LuanState implements DeepCloneable<LuanState> { @@ -141,7 +132,7 @@ try { LuanState luan = LuanCompiler.newLuanState(); luan.globalImport("Package"); - BasicLib.do_file(luan,"java:luan/lib/init.luan"); + BasicLib.do_file(luan,"java:luan/init.luan"); return luan; } catch(LuanException e) { throw new RuntimeException(e);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/init.luan Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,107 @@ +function Package.global(module,fn_name) + local function fn(...) + return module[fn_name](...) + end + _G[fn_name] = fn + return fn +end + +local require = Package.global(Package,"require") + +function Package.global_import(name) + local mod = require(name) + _G[name] = mod + return mod +end + +local Basic = Package.global_import("Basic","luan.lib.BasicLib.LOADER") +Package.global(Basic,"assert") +Package.global(Basic,"assert_boolean") +Package.global(Basic,"assert_nil") +Package.global(Basic,"assert_number") +Package.global(Basic,"assert_string") +Package.global(Basic,"assert_table") +Package.global(Basic,"do_file") +Package.global(Basic,"error") +Package.global(Basic,"get_metatable") +Package.global(Basic,"ipairs") +local load = Package.global(Basic,"load") +Package.global(Basic,"load_file") +Package.global(Basic,"pairs") +Package.global(Basic,"range") +Package.global(Basic,"raw_equal") +Package.global(Basic,"raw_get") +Package.global(Basic,"raw_len") +Package.global(Basic,"raw_set") +Package.global(Basic,"repr") +Package.global(Basic,"set_metatable") +Package.global(Basic,"to_number") +local to_string = Package.global(Basic,"to_string") +Package.global(Basic,"type") + +local String = Package.global_import("String","luan.lib.StringLib.LOADER") + +-- improved global_import +function Package.global_import(name) + local short = name.match("\.([^.]+)$") or name + local mod = require(name) + _G[short] = mod + return mod +end + +local Table = Package.global_import("Table","luan.lib.TableLib.LOADER") +local Io = Package.global_import("Io","luan.lib.IoLib.LOADER") +Package.global_import("Math","luan.lib.MathLib.LOADER") +Package.global_import("Html","luan.lib.HtmlLib.LOADER") +Package.global_import("Thread","luan.lib.ThreadLib.LOADER") +Package.global_import("Binary","luan.lib.BinaryLib.LOADER") + + +function Io.print_to(out,...) + local list = {} + for _,v in Basic.values(...) do + list[#list+1] = to_string(v) + list[#list+1] = '\t' + end + if #list == 0 then + out.write( '\n' ) + else + list[#list] = '\n' + out.write( Table.unpack(list) ) + end +end + +function Basic.print(...) + Io.print_to(Io.stdout,...) +end +local print = Package.global(Basic,"print") + +local Debug = {} +Package.loaded.Debug = Debug +_G.Debug = Debug + +function Debug.print_if_something(...) + if Table.pack(...).n > 0 then + print(...) + end +end + +function Debug.debug(prompt) + prompt = prompt or "luan_debug> " + local function console() + return Io.read_console_line(prompt) + end + local env = {} + for line in console do + try + local fn = load(line,"stdin",env,true) + Debug.print_if_something( fn() ) + catch e do + print(e) + end + end +end + + +-- import modules +Package.global_import("Reactionary")
--- a/src/luan/lib/BasicLib.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ -package luan.lib; - -import java.io.File; -import java.io.InputStreamReader; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.Iterator; -import java.util.Map; -import java.util.List; -import java.util.ArrayList; -import luan.Luan; -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanException; -import luan.LuanSource; -import luan.LuanElement; -import luan.impl.LuanCompiler; - - -public final class BasicLib { - - public static final LuanFunction LOADER = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - LuanTable module = new LuanTable(); - try { - module.put( "assert", new LuanJavaFunction(BasicLib.class.getMethod("assert_",LuanState.class,Object.class,String.class),null) ); - add( module, "assert_boolean", LuanState.class, Boolean.TYPE ); - add( module, "assert_nil", LuanState.class, Object.class ); - add( module, "assert_number", LuanState.class, Number.class ); - add( module, "assert_string", LuanState.class, String.class ); - add( module, "assert_table", LuanState.class, LuanTable.class ); - add( module, "do_file", LuanState.class, String.class ); - add( module, "error", LuanState.class, Object.class ); - add( module, "get_metatable", LuanState.class, Object.class ); - add( module, "ipairs", LuanState.class, LuanTable.class ); - add( module, "load", LuanState.class, String.class, String.class, LuanTable.class, Boolean.class ); - add( module, "load_file", LuanState.class, String.class ); - add( module, "pairs", LuanState.class, LuanTable.class ); - add( module, "range", LuanState.class, Double.TYPE, Double.TYPE, Double.class ); - add( module, "raw_equal", Object.class, Object.class ); - add( module, "raw_get", LuanTable.class, Object.class ); - add( module, "raw_len", LuanState.class, Object.class ); - add( module, "raw_set", LuanTable.class, Object.class, Object.class ); - add( module, "repr", LuanState.class, Object.class ); - add( module, "set_metatable", LuanTable.class, LuanTable.class ); - add( module, "to_number", Object.class, Integer.class ); - add( module, "to_string", LuanState.class, Object.class ); - add( module, "type", Object.class ); - add( module, "values", new Object[0].getClass() ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return module; - } - }; - - private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { - t.put( method, new LuanJavaFunction(BasicLib.class.getMethod(method,parameterTypes),null) ); - } - - public static String type(Object obj) { - return Luan.type(obj); - } - - public static LuanFunction load(LuanState luan,String text,String sourceName,LuanTable env,Boolean allowExpr) - throws LuanException - { - if( allowExpr==null ) - allowExpr = false; - return LuanCompiler.compile(luan,new LuanSource(sourceName,text),env,allowExpr); - } - - public static LuanFunction load_file(LuanState luan,String fileName) throws LuanException { - try { - String src = fileName==null ? Utils.readAll(new InputStreamReader(System.in)) : IoLib.luanIo(luan,fileName).read_text(); - return load(luan,src,fileName,null,false); - } catch(IOException e) { - throw luan.exception(e); - } - } - - public static Object do_file(LuanState luan,String fileName) throws LuanException { - LuanFunction fn = load_file(luan,fileName); - return luan.call(fn); - } - - private static LuanFunction pairs(final Iterator<Map.Entry<Object,Object>> iter) { - return new LuanFunction() { - @Override public Object[] call(LuanState luan,Object[] args) { - if( !iter.hasNext() ) - return LuanFunction.NOTHING; - Map.Entry<Object,Object> entry = iter.next(); - return new Object[]{entry.getKey(),entry.getValue()}; - } - }; - } - - public static LuanFunction pairs(LuanState luan,LuanTable t) throws LuanException { - Utils.checkNotNull(luan,t,"table"); - return pairs( t.iterator() ); - } - - public static LuanFunction ipairs(LuanState luan,LuanTable t) throws LuanException { - Utils.checkNotNull(luan,t,"table"); - return pairs( t.listIterator() ); - } - - public static LuanTable get_metatable(LuanState luan,Object obj) { - return luan.getMetatable(obj); - } - - public static LuanTable set_metatable(LuanTable table,LuanTable metatable) { - table.setMetatable(metatable); - return table; - } - - public static boolean raw_equal(Object v1,Object v2) { - return v1 == v2 || v1 != null && v1.equals(v2); - } - - public static Object raw_get(LuanTable table,Object index) { - return table.get(index); - } - - public static LuanTable raw_set(LuanTable table,Object index,Object value) { - table.put(index,value); - return table; - } - - public static int raw_len(LuanState luan,Object v) throws LuanException { - if( v instanceof String ) { - String s = (String)v; - return s.length(); - } - if( v instanceof LuanTable ) { - LuanTable t = (LuanTable)v; - return t.length(); - } - throw luan.exception( "bad argument #1 to 'raw_len' (table or string expected)" ); - } - - public static Number to_number(Object e,Integer base) { - return Luan.toNumber(e,base); - } - - public static String to_string(LuanState luan,Object v) throws LuanException { - return luan.toString(v); - } - - public static void error(LuanState luan,Object msg) throws LuanException { - throw luan.exception(msg); - } - - public static Object assert_(LuanState luan,Object v,String msg) throws LuanException { - if( Luan.toBoolean(v) ) - return v; - if( msg == null ) - msg = "assertion failed!"; - throw luan.exception( msg ); - } - - public static String assert_string(LuanState luan,String v) throws LuanException { - Utils.checkNotNull(luan,v,"string"); - return v; - } - - public static Number assert_number(LuanState luan,Number v) throws LuanException { - Utils.checkNotNull(luan,v,"number"); - return v; - } - - public static LuanTable assert_table(LuanState luan,LuanTable v) throws LuanException { - Utils.checkNotNull(luan,v,"table"); - return v; - } - - public static boolean assert_boolean(LuanState luan,boolean v) throws LuanException { - return v; - } - - public static Object assert_nil(LuanState luan,Object v) throws LuanException { - if( v != null ) - throw luan.exception("bad argument #1 (nil expected, got "+Luan.type(v)+")"); - return v; - } - - public static String repr(LuanState luan,Object v) throws LuanException { - return luan.repr(v); - } - - public static LuanFunction range(LuanState luan,final double from,final double to,Double stepV) throws LuanException { - final double step = stepV==null ? 1.0 : stepV; - if( step == 0.0 ) - throw luan.exception("bad argument #3 (step may not be zero)"); - return new LuanFunction() { - double v = from; - - @Override public Object call(LuanState luan,Object[] args) { - if( step > 0.0 && v > to || step < 0.0 && v < to ) - return LuanFunction.NOTHING; - double rtn = v; - v += step; - return rtn; - } - }; - } - - public static LuanFunction values(final Object... args) throws LuanException { - return new LuanFunction() { - int i = 0; - - @Override public Object call(LuanState luan,Object[] unused) { - if( ++i > args.length ) - return LuanFunction.NOTHING; - return new Object[]{i,args[i-1]}; - } - }; - } - -}
--- a/src/luan/lib/BinaryLib.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -package luan.lib; - -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanException; - - -public final class BinaryLib { - - public static final LuanFunction LOADER = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - LuanTable module = new LuanTable(); - try { - add( module, "to_string", new byte[0].getClass() ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return module; - } - }; - - private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { - t.put( method, new LuanJavaFunction(BinaryLib.class.getMethod(method,parameterTypes),null) ); - } - - public static String to_string(byte[] bytes) { - return new String(bytes); - } - -}
--- a/src/luan/lib/HtmlLib.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -package luan.lib; - -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanException; - - -public final class HtmlLib { - - public static final LuanFunction LOADER = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - LuanTable module = new LuanTable(); - try { - add( module, "encode", String.class ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return module; - } - }; - - private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { - t.put( method, new LuanJavaFunction(HtmlLib.class.getMethod(method,parameterTypes),null) ); - } - - public static String encode(String s) { - char[] a = s.toCharArray(); - StringBuilder buf = new StringBuilder(); - for( int i=0; i<a.length; i++ ) { - char c = a[i]; - switch(c) { - case '&': - buf.append("&"); - break; - case '<': - buf.append("<"); - break; - case '>': - buf.append(">"); - break; - case '"': - buf.append("""); - break; - default: - buf.append(c); - } - } - return buf.toString(); - } - -}
--- a/src/luan/lib/HttpLib.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,285 +0,0 @@ -package luan.lib; - -import java.io.PrintWriter; -import java.io.IOException; -import java.util.Map; -import java.util.Set; -import java.util.Arrays; -import java.util.Enumeration; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import luan.Luan; -import luan.LuanState; -import luan.LuanFunction; -import luan.LuanElement; -import luan.LuanException; -import luan.LuanTable; -import luan.LuanJavaFunction; -import luan.LuanExitException; -import luan.DeepCloner; - - -public final class HttpLib { - - public static final LuanFunction LOADER = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - return new LuanTable(); // starts empty - } - }; - - public static void service(LuanState luan,HttpServletRequest request,HttpServletResponse response,String modName) - throws LuanException - { - LuanFunction fn; - synchronized(luan) { - Object mod = PackageLib.require(luan,modName); - if( !(mod instanceof LuanTable) ) - throw luan.exception( "module '"+modName+"' must return a table" ); - LuanTable tbl = (LuanTable)mod; - if( Luan.toBoolean( tbl.get("per_session") ) ) { - HttpSession session = request.getSession(); - LuanState sessionLuan = (LuanState)session.getValue("luan"); - if( sessionLuan!=null ) { - luan = sessionLuan; - } else { - DeepCloner cloner = new DeepCloner(); - luan = cloner.deepClone(luan); - session.putValue("luan",luan); - } - tbl = (LuanTable)PackageLib.require(luan,modName); - fn = (LuanFunction)tbl.get("page"); - } else { - fn = (LuanFunction)tbl.get("page"); - if( fn == null ) - throw luan.exception( "function 'page' is not defined" ); - DeepCloner cloner = new DeepCloner(); - luan = cloner.deepClone(luan); - fn = cloner.get(fn); - } - } - - LuanTable module = (LuanTable)luan.loaded().get("Http"); - if( module == null ) - throw luan.exception( "module 'Http' not defined" ); - HttpLib lib = new HttpLib(request,response); - try { - module.put( "request", lib.requestTable() ); - module.put( "response", lib.responseTable() ); -/* - module.put( "write", new LuanJavaFunction( - HttpLib.class.getMethod( "text_write", LuanState.class, new Object[0].getClass() ), lib - ) ); -*/ - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - - luan.call(fn,"<http>"); - } - - - - private final HttpServletRequest request; - private final HttpServletResponse response; -// private PrintWriter writer = null; -// private ServletOutputStream sos = null; - - private HttpLib(HttpServletRequest request,HttpServletResponse response) { - this.request = request; - this.response = response; - } - - private LuanTable requestTable() throws NoSuchMethodException { - LuanTable req = new LuanTable(); - req.put("java",request); - req.put( "get_attribute", new LuanJavaFunction(HttpServletRequest.class.getMethod("getAttribute",String.class),request) ); - req.put( "set_attribute", new LuanJavaFunction(HttpServletRequest.class.getMethod("setAttribute",String.class,Object.class),request) ); - req.put( "get_parameter", new LuanJavaFunction(HttpServletRequest.class.getMethod("getParameter",String.class),request) ); - req.put( "get_parameter_values", new LuanJavaFunction(HttpServletRequest.class.getMethod("getParameterValues",String.class),request) ); - req.put( "get_header", new LuanJavaFunction(HttpServletRequest.class.getMethod("getHeader",String.class),request) ); - add( req, "get_cookie_value", String.class ); - req.put( "method", new LuanJavaFunction(HttpServletRequest.class.getMethod("getMethod"),request) ); - req.put( "servlet_path", new LuanJavaFunction(HttpServletRequest.class.getMethod("getServletPath"),request) ); - req.put( "server_name", new LuanJavaFunction(HttpServletRequest.class.getMethod("getServerName"),request) ); - add( req, "current_url" ); - req.put( "remote_address", new LuanJavaFunction(HttpServletRequest.class.getMethod("getRemoteAddr"),request) ); - add( req, "get_session_attribute", String.class ); - add( req, "set_session_attribute", String.class, Object.class ); - return req; - } - - private LuanTable responseTable() throws NoSuchMethodException { - LuanTable resp = new LuanTable(); - resp.put("java",response); - add( resp, "send_redirect", String.class ); - add( resp, "send_error", Integer.TYPE, String.class ); - resp.put( "contains_header", new LuanJavaFunction(HttpServletResponse.class.getMethod("containsHeader",String.class),response) ); - resp.put( "set_header", new LuanJavaFunction(HttpServletResponse.class.getMethod("setHeader",String.class,String.class),response) ); - add( resp, "set_cookie", String.class, String.class, Boolean.TYPE, String.class ); - add( resp, "remove_cookie", String.class, String.class ); - resp.put( "set_content_type", new LuanJavaFunction(HttpServletResponse.class.getMethod("setContentType",String.class),response) ); - add( resp, "text_writer" ); - return resp; - } - - private void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { - t.put( method, new LuanJavaFunction(HttpLib.class.getMethod(method,parameterTypes),this) ); - } -/* - public void text_write(LuanState luan,Object... args) throws LuanException, IOException { - if( writer == null ) - writer = response.getWriter(); - for( Object obj : args ) { - writer.print( luan.toString(obj) ); - } - } -*/ - public LuanTable text_writer() throws IOException { - return IoLib.textWriter(response.getWriter()); - } - - public String get_cookie_value(String name) { - return getCookieValue(request, name); - } - - public String current_url() { - return getCurrentURL(request); - } - - public void send_redirect(String redirectUrl) - throws IOException - { - response.sendRedirect(redirectUrl); - throw new LuanExitException(); - } - - public void send_error(int code,String text) - throws IOException - { - response.sendError(code, text); - throw new LuanExitException(); - } - - public void set_cookie(String name,String value,boolean isPersistent, String domain) { - setCookie(request,response,name,value,isPersistent,domain); - } - - public void remove_cookie(String name, String domain) { - removeCookie(request,response,name,domain); - } - - public Object get_session_attribute(String name) { - return request.getSession().getAttribute(name); - } - - public void set_session_attribute(String name,Object value) { - request.getSession().setAttribute(name,value); - } - - - // static utils - - public static String getQueryString(HttpServletRequest request) { - return getQueryString(request,0); - } - - public static String getQueryString(HttpServletRequest request,int maxValueLen) { - String method = request.getMethod(); - if( method.equals("GET") ) - return request.getQueryString(); - if( !method.equals("POST") && !method.equals("HEAD") ) - throw new RuntimeException(method); - Enumeration en = request.getParameterNames(); - StringBuilder queryBuf = new StringBuilder(); - if( !en.hasMoreElements() ) - return null; - do { - String param = (String)en.nextElement(); - String value = request.getParameter(param); - if( maxValueLen > 0 ) { - int len = value.length(); - if( len > maxValueLen ) - value = value.substring(0,maxValueLen) + "..." + (len-maxValueLen); - } - queryBuf.append(param); - queryBuf.append('='); - queryBuf.append(value); - queryBuf.append('&'); - } while( en.hasMoreElements() ); - queryBuf.deleteCharAt(queryBuf.length() - 1); - return queryBuf.toString(); - } - - public static String getCurrentURL(HttpServletRequest request) { - return getCurrentURL(request,0); - } - - public static String getCurrentURL(HttpServletRequest request,int maxValueLen) { -// StringBuffer buf = HttpUtils.getRequestURL(request); - StringBuffer buf = request.getRequestURL(); - String qStr = getQueryString(request,maxValueLen); - if(qStr != null && qStr.length() > 0) { - buf.append('?'); - buf.append(qStr); - } - return buf.toString(); - } - - private static String escape(String value) { - return value.replaceAll(";", "%3B"); - } - - private static String unescape(String value) { - return value.replaceAll("%3B", ";"); - } - - private static Cookie getCookie(HttpServletRequest request,String name) { - Cookie[] cookies = request.getCookies(); - if( cookies == null ) - return null; - for (Cookie cookie : cookies) { - if (cookie.getName().equals(name)) - return cookie; - } - return null; - } - - public static String getCookieValue(HttpServletRequest request,String name) { - Cookie cookie = getCookie(request,name); - return cookie==null ? null : unescape(cookie.getValue()); - } - - public static void setCookie(HttpServletRequest request,HttpServletResponse response,String name,String value,boolean isPersistent, String domain) { - Cookie cookie = getCookie(request,name); - if( cookie==null || !cookie.getValue().equals(value) ) { - cookie = new Cookie(name, escape(value)); - cookie.setPath("/"); - if (domain != null && domain.length() > 0) - cookie.setDomain(domain); - if( isPersistent ) - cookie.setMaxAge(10000000); - response.addCookie(cookie); - } - } - - public static void removeCookie(HttpServletRequest request, - HttpServletResponse response, - String name, - String domain - - ) { - Cookie cookie = getCookie(request, name); - if(cookie != null) { - Cookie delCookie = new Cookie(name, "delete"); - delCookie.setPath("/"); - delCookie.setMaxAge(0); - if (domain != null && domain.length() > 0) - delCookie.setDomain(domain); - response.addCookie(delCookie); - } - } - -}
--- a/src/luan/lib/IoLib.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,504 +0,0 @@ -package luan.lib; - -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.Reader; -import java.io.Writer; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.net.URL; -import java.net.Socket; -import java.net.ServerSocket; -import java.net.MalformedURLException; -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanException; - - -public final class IoLib { - - public static final LuanFunction LOADER = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - LuanTable module = new LuanTable(); - try { - add( module, "File", LuanState.class, String.class ); - add( module, "read_console_line", String.class ); - - LuanTable stdin = new LuanTable(); - stdin.put( "read_text", new LuanJavaFunction( - IoLib.class.getMethod( "stdin_read_text" ), null - ) ); - stdin.put( "read_binary", new LuanJavaFunction( - IoLib.class.getMethod( "stdin_read_binary" ), null - ) ); - stdin.put( "read_lines", new LuanJavaFunction( - IoLib.class.getMethod( "stdin_read_lines" ), null - ) ); - stdin.put( "read_blocks", new LuanJavaFunction( - IoLib.class.getMethod( "stdin_read_blocks", Integer.class ), null - ) ); - module.put( "stdin", stdin ); - - add( module, "Socket", String.class, Integer.TYPE ); - add( module, "socket_server", Integer.TYPE ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - module.put( "stdout", textWriter(System.out) ); - module.put( "stderr", textWriter(System.err) ); - return module; - } - }; - - private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { - t.put( method, new LuanJavaFunction(IoLib.class.getMethod(method,parameterTypes),null) ); - } - - - public static String stdin_read_text() throws IOException { - return Utils.readAll(new InputStreamReader(System.in)); - } - - public static byte[] stdin_read_binary() throws IOException { - return Utils.readAll(System.in); - } - - public static LuanFunction stdin_read_lines() throws IOException { - return lines(new BufferedReader(new InputStreamReader(System.in))); - } - - public static LuanFunction stdin_read_blocks(Integer blockSize) throws IOException { - int n = blockSize!=null ? blockSize : Utils.bufSize; - return blocks(System.in,n); - } - - public static String read_console_line(String prompt) throws IOException { - if( prompt==null ) - prompt = "> "; - return System.console().readLine(prompt); - } - - - public interface LuanWriter { - public void write(LuanState luan,Object... args) throws LuanException, IOException; - public void close() throws IOException; - } - - public static LuanTable textWriter(final PrintStream out) { - LuanWriter luanWriter = new LuanWriter() { - - public void write(LuanState luan,Object... args) throws LuanException { - for( Object obj : args ) { - out.print( luan.toString(obj) ); - } - } - - public void close() { - out.close(); - } - }; - return writer(luanWriter); - } - - public static LuanTable textWriter(final Writer out) { - LuanWriter luanWriter = new LuanWriter() { - - public void write(LuanState luan,Object... args) throws LuanException, IOException { - for( Object obj : args ) { - out.write( luan.toString(obj) ); - } - } - - public void close() throws IOException { - out.close(); - } - }; - return writer(luanWriter); - } - - private static LuanTable writer(LuanWriter luanWriter) { - LuanTable writer = new LuanTable(); - try { - writer.put( "write", new LuanJavaFunction( - LuanWriter.class.getMethod( "write", LuanState.class, new Object[0].getClass() ), luanWriter - ) ); - writer.put( "close", new LuanJavaFunction( - LuanWriter.class.getMethod( "close" ), luanWriter - ) ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return writer; - } - - - public static LuanTable binaryWriter(final OutputStream out) { - LuanTable writer = new LuanTable(); - try { - writer.put( "write", new LuanJavaFunction( - OutputStream.class.getMethod( "write", new byte[0].getClass() ), out - ) ); - writer.put( "close", new LuanJavaFunction( - OutputStream.class.getMethod( "close" ), out - ) ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return writer; - } - - static LuanFunction lines(final BufferedReader in) { - return new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) throws LuanException { - try { - if( args.length > 0 ) { - if( args.length > 1 || !"close".equals(args[0]) ) - throw luan.exception( "the only argument allowed is 'close'" ); - in.close(); - return null; - } - String rtn = in.readLine(); - if( rtn==null ) - in.close(); - return rtn; - } catch(IOException e) { - throw luan.exception(e); - } - } - }; - } - - static LuanFunction blocks(final InputStream in,final int blockSize) { - return new LuanFunction() { - final byte[] a = new byte[blockSize]; - - @Override public Object call(LuanState luan,Object[] args) throws LuanException { - try { - if( args.length > 0 ) { - if( args.length > 1 || !"close".equals(args[0]) ) - throw luan.exception( "the only argument allowed is 'close'" ); - in.close(); - return null; - } - if( in.read(a) == -1 ) { - in.close(); - return null; - } - return a; - } catch(IOException e) { - throw luan.exception(e); - } - } - }; - } - - - - public static abstract class LuanIn { - abstract InputStream inputStream() throws IOException; - public abstract String to_string(); - - public String read_text() throws IOException { - Reader in = new InputStreamReader(inputStream()); - String s = Utils.readAll(in); - in.close(); - return s; - } - - public byte[] read_binary() throws IOException { - InputStream in = inputStream(); - byte[] a = Utils.readAll(in); - in.close(); - return a; - } - - public LuanFunction read_lines() throws IOException { - return lines(new BufferedReader(new InputStreamReader(inputStream()))); - } - - public LuanFunction read_blocks(Integer blockSize) throws IOException { - int n = blockSize!=null ? blockSize : Utils.bufSize; - return blocks(inputStream(),n); - } - - LuanTable table() { - LuanTable tbl = new LuanTable(); - try { - tbl.put( "to_string", new LuanJavaFunction( - LuanIn.class.getMethod( "to_string" ), this - ) ); - tbl.put( "read_text", new LuanJavaFunction( - LuanIn.class.getMethod( "read_text" ), this - ) ); - tbl.put( "read_binary", new LuanJavaFunction( - LuanIn.class.getMethod( "read_binary" ), this - ) ); - tbl.put( "read_lines", new LuanJavaFunction( - LuanIn.class.getMethod( "read_lines" ), this - ) ); - tbl.put( "read_blocks", new LuanJavaFunction( - LuanIn.class.getMethod( "read_blocks", Integer.class ), this - ) ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return tbl; - } - } - - public static abstract class LuanIO extends LuanIn { - abstract OutputStream outputStream() throws IOException; - - public void write(LuanState luan,Object obj) throws LuanException, IOException { - if( obj instanceof String ) { - String s = (String)obj; - Writer out = new OutputStreamWriter(outputStream()); - out.write(s); - out.close(); - return; - } - if( obj instanceof byte[] ) { - byte[] a = (byte[])obj; - OutputStream out = outputStream(); - Utils.copyAll(new ByteArrayInputStream(a),out); - out.close(); - return; - } - throw luan.exception( "bad argument #1 to 'write' (string or binary expected)" ); - } - - public LuanTable text_writer() throws IOException { - return textWriter(new BufferedWriter(new OutputStreamWriter(outputStream()))); - } - - public LuanTable binary_writer() throws IOException { - return binaryWriter(new BufferedOutputStream(outputStream())); - } - - @Override LuanTable table() { - LuanTable tbl = super.table(); - try { - tbl.put( "write", new LuanJavaFunction( - LuanIO.class.getMethod( "write", LuanState.class, Object.class ), this - ) ); - tbl.put( "text_writer", new LuanJavaFunction( - LuanIO.class.getMethod( "text_writer" ), this - ) ); - tbl.put( "binary_writer", new LuanJavaFunction( - LuanIO.class.getMethod( "binary_writer" ), this - ) ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return tbl; - } - } - - public static final class LuanUrl extends LuanIn { - private final URL url; - - public LuanUrl(String s) throws MalformedURLException { - this.url = new URL(s); - } - - @Override InputStream inputStream() throws IOException { - return url.openStream(); - } - - @Override public String to_string() { - return url.toString(); - } - } - - public static final class LuanFile extends LuanIO { - private final File file; - - public LuanFile(String name) { - this(new File(name)); - } - - public LuanFile(File file) { - this.file = file; - } - - @Override InputStream inputStream() throws IOException { - return new FileInputStream(file); - } - - @Override OutputStream outputStream() throws IOException { - return new FileOutputStream(file); - } - - @Override public String to_string() { - return file.toString(); - } - - public LuanTable child(String name) { - return new LuanFile(new File(file,name)).table(); - } - - public LuanTable children() { - File[] files = file.listFiles(); - if( files==null ) - return null; - LuanTable list = new LuanTable(); - for( File f : files ) { - list.add(new LuanFile(f).table()); - } - return list; - } - - public boolean exists() { - return Utils.exists(file); - } - - @Override LuanTable table() { - LuanTable tbl = super.table(); - try { - tbl.put( "name", new LuanJavaFunction( - File.class.getMethod( "getName" ), file - ) ); - tbl.put( "exists", new LuanJavaFunction( - LuanFile.class.getMethod( "exists" ), this - ) ); - tbl.put( "is_directory", new LuanJavaFunction( - File.class.getMethod( "isDirectory" ), file - ) ); - tbl.put( "is_file", new LuanJavaFunction( - File.class.getMethod( "isFile" ), file - ) ); - tbl.put( "delete", new LuanJavaFunction( - File.class.getMethod( "delete" ), file - ) ); - tbl.put( "mkdir", new LuanJavaFunction( - File.class.getMethod( "mkdir" ), file - ) ); - tbl.put( "mkdirs", new LuanJavaFunction( - File.class.getMethod( "mkdirs" ), file - ) ); - tbl.put( "last_modified", new LuanJavaFunction( - File.class.getMethod( "lastModified" ), file - ) ); - tbl.put( "child", new LuanJavaFunction( - LuanFile.class.getMethod( "child", String.class ), this - ) ); - tbl.put( "children", new LuanJavaFunction( - LuanFile.class.getMethod( "children" ), this - ) ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return tbl; - } - } - - public static LuanIn luanIo(LuanState luan,String name) throws LuanException { - if( Utils.isFile(name) ) - return new LuanFile(name); - String url = Utils.toUrl(name); - if( url != null ) { - try { - return new LuanUrl(url); - } catch(MalformedURLException e) { - throw new RuntimeException(e); - } - } - throw luan.exception( "file '"+name+"' not found" ); - } - - public static LuanTable File(LuanState luan,String name) throws LuanException { - return luanIo(luan,name).table(); - } - - public static final class LuanSocket extends LuanIO { - private final Socket socket; - - public LuanSocket(String host,int port) throws IOException { - this(new Socket(host,port)); - } - - public LuanSocket(Socket socket) throws IOException { - this.socket = socket; - } - - @Override InputStream inputStream() throws IOException { - return socket.getInputStream(); - } - - @Override OutputStream outputStream() throws IOException { - return socket.getOutputStream(); - } - - @Override public String to_string() { - return socket.toString(); - } - - public LuanTable Pickle_client(LuanState luan) throws IOException { - DataInputStream in = new DataInputStream(new BufferedInputStream(inputStream())); - DataOutputStream out = new DataOutputStream(new BufferedOutputStream(outputStream())); - return new PickleClient(luan,in,out).table(); - } - - public void run_pickle_server(LuanState luan) throws IOException { - DataInputStream in = new DataInputStream(new BufferedInputStream(inputStream())); - DataOutputStream out = new DataOutputStream(new BufferedOutputStream(outputStream())); - new PickleServer(luan,in,out).run(); - } - - @Override LuanTable table() { - LuanTable tbl = super.table(); - try { - tbl.put( "Pickle_client", new LuanJavaFunction( - LuanSocket.class.getMethod( "Pickle_client", LuanState.class ), this - ) ); - tbl.put( "run_pickle_server", new LuanJavaFunction( - LuanSocket.class.getMethod( "run_pickle_server", LuanState.class ), this - ) ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return tbl; - } - } - - public static LuanTable Socket(String host,int port) throws IOException { - return new LuanSocket(host,port).table(); - } - - public static LuanFunction socket_server(int port) throws IOException { - final ServerSocket ss = new ServerSocket(port); - return new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) throws LuanException { - try { - if( args.length > 0 ) { - if( args.length > 1 || !"close".equals(args[0]) ) - throw luan.exception( "the only argument allowed is 'close'" ); - ss.close(); - return null; - } - return new LuanSocket(ss.accept()).table(); - } catch(IOException e) { - throw luan.exception(e); - } - } - }; - } - - private void IoLib() {} // never -}
--- a/src/luan/lib/JavaLib.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,450 +0,0 @@ -package luan.lib; - -import java.lang.reflect.Array; -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Member; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Constructor; -import java.lang.reflect.Modifier; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Collections; -import java.util.Arrays; -import luan.Luan; -import luan.LuanState; -import luan.LuanTable; -import luan.MetatableGetter; -import luan.LuanException; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanElement; - - -public final class JavaLib { - - public static final LuanFunction LOADER = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - luan.addMetatableGetter(mg); - LuanTable module = new LuanTable(); - try { - module.put( "class", new LuanJavaFunction(JavaLib.class.getMethod("getClass",LuanState.class,String.class),null) ); - add( module, "proxy", LuanState.class, Static.class, LuanTable.class, Object.class ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - luan.searchers().add(javaSearcher); - return module; - } - }; - - public static final LuanFunction javaSearcher = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) throws LuanException { - String modName = (String)args[0]; - final Static s = JavaLib.getClass(luan,modName); - if( s==null ) - return null; - LuanFunction loader = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - return s; - } - }; - return loader; - } - }; - - private static void add(LuanTable t,String method,Class<?>... parameterTypes) { - try { - t.put( method, new LuanJavaFunction(JavaLib.class.getMethod(method,parameterTypes),null) ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - private static final LuanTable mt = new LuanTable(); - static { - add( mt, "__index", LuanState.class, Object.class, Object.class ); - add( mt, "__newindex", LuanState.class, Object.class, Object.class, Object.class ); - } - - private static final MetatableGetter mg = new MetatableGetter() { - public LuanTable getMetatable(Object obj) { - if( obj==null ) - return null; - return mt; - } - }; - - public static Object __index(LuanState luan,Object obj,Object key) throws LuanException { - if( obj instanceof Static ) { - if( key instanceof String ) { - String name = (String)key; - Static st = (Static)obj; - Class cls = st.cls; - if( "class".equals(name) ) { - return cls; - } else if( "new".equals(name) ) { - Constructor<?>[] constructors = cls.getConstructors(); - if( constructors.length > 0 ) { - if( constructors.length==1 ) { - return new LuanJavaFunction(constructors[0],null); - } else { - List<LuanJavaFunction> fns = new ArrayList<LuanJavaFunction>(); - for( Constructor constructor : constructors ) { - fns.add(new LuanJavaFunction(constructor,null)); - } - return new AmbiguousJavaFunction(fns); - } - } - } else if( "assert".equals(name) ) { - return new LuanJavaFunction(assertClass,new AssertClass(cls)); - } else { - List<Member> members = getStaticMembers(cls,name); - if( !members.isEmpty() ) { - return member(null,members); - } - } - } - throw luan.exception("invalid member '"+key+"' for: "+obj); - } - Class cls = obj.getClass(); - if( cls.isArray() ) { - if( "length".equals(key) ) { - return Array.getLength(obj); - } - Integer i = Luan.asInteger(key); - if( i != null ) { - return Array.get(obj,i); - } - throw luan.exception("invalid member '"+key+"' for java array: "+obj); - } - if( key instanceof String ) { - String name = (String)key; - if( "instanceof".equals(name) ) { - return new LuanJavaFunction(instanceOf,new InstanceOf(obj)); - } else { - List<Member> members = getMembers(cls,name); - if( !members.isEmpty() ) { - return member(obj,members); - } - } - } -// throw luan.exception("invalid member '"+key+"' for java object: "+obj); - return null; - } - - private static Object member(Object obj,List<Member> members) throws LuanException { - try { - if( members.size()==1 ) { - Member member = members.get(0); - if( member instanceof Static ) { - return member; - } else if( member instanceof Field ) { - Field field = (Field)member; - Object rtn = field.get(obj); - return rtn instanceof Object[] ? Arrays.asList((Object[])rtn) : rtn; - } else { - Method method = (Method)member; - return new LuanJavaFunction(method,obj); - } - } else { - List<LuanJavaFunction> fns = new ArrayList<LuanJavaFunction>(); - for( Member member : members ) { - Method method = (Method)member; - fns.add(new LuanJavaFunction(method,obj)); - } - return new AmbiguousJavaFunction(fns); - } - } catch(IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - public static void __newindex(LuanState luan,Object obj,Object key,Object value) throws LuanException { - if( obj instanceof Static ) { - if( key instanceof String ) { - String name = (String)key; - Static st = (Static)obj; - Class cls = st.cls; - List<Member> members = getStaticMembers(cls,name); - if( !members.isEmpty() ) { - if( members.size() != 1 ) - throw new RuntimeException("not field '"+name+"' of "+obj); - setMember(obj,members,value); - return; - } - } - throw luan.exception("invalid member '"+key+"' for: "+obj); - } - Class cls = obj.getClass(); - if( cls.isArray() ) { - Integer i = Luan.asInteger(key); - if( i != null ) { - Array.set(obj,i,value); - return; - } - throw luan.exception("invalid member '"+key+"' for java array: "+obj); - } - if( key instanceof String ) { - String name = (String)key; - List<Member> members = getMembers(cls,name); - if( !members.isEmpty() ) { - if( members.size() != 1 ) - throw new RuntimeException("not field '"+name+"' of "+obj); - setMember(obj,members,value); - return; - } - } - throw luan.exception("invalid member '"+key+"' for java object: "+obj); - } - - private static void setMember(Object obj,List<Member> members,Object value) { - Field field = (Field)members.get(0); - try { - try { - field.set(obj,value); - } catch(IllegalArgumentException e) { - Class cls = field.getType(); - if( value instanceof Number ) { - Number n = (Number)value; - if( cls.equals(Integer.TYPE) || cls.equals(Integer.class) ) { - int r = n.intValue(); - if( r==n.doubleValue() ) { - field.setInt(obj,r); - return; - } - } - } - throw e; - } - } catch(IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - public static boolean privateAccess = false; - private static Map<Class,Map<String,List<Member>>> memberMap = new HashMap<Class,Map<String,List<Member>>>(); - - private static synchronized List<Member> getMembers(Class cls,String name) { - Map<String,List<Member>> clsMap = memberMap.get(cls); - if( clsMap == null ) { - clsMap = new HashMap<String,List<Member>>(); - for( Class c : cls.getClasses() ) { - String s = c.getSimpleName(); - List<Member> list = new ArrayList<Member>(); - clsMap.put(s,list); - list.add(new Static(c)); - } - for( Field field : cls.getFields() ) { - String s = field.getName(); - try { - if( !cls.getField(s).equals(field) ) - continue; // not accessible - } catch(NoSuchFieldException e) { - throw new RuntimeException(e); - } - List<Member> list = new ArrayList<Member>(); - clsMap.put(s,list); - list.add(field); - } - for( Method method : cls.getMethods() ) { - String s = method.getName(); - List<Member> list = clsMap.get(s); - if( list == null || !(list.get(0) instanceof Method) ) { - list = new ArrayList<Member>(); - clsMap.put(s,list); - } - list.add(method); - } - if( privateAccess ) { - for( Method method : cls.getDeclaredMethods() ) { - String s = method.getName(); - List<Member> list = clsMap.get(s); - if( list == null ) { - list = new ArrayList<Member>(); - clsMap.put(s,list); - } else if( !(list.get(0) instanceof Method) ) - continue; - if( !list.contains(method) ) { - list.add(method); - } - } - for( Field field : cls.getDeclaredFields() ) { - String s = field.getName(); - List<Member> list = clsMap.get(s); - if( list == null ) { - list = new ArrayList<Member>(); - clsMap.put(s,list); - list.add(field); - } - } - } - for( List<Member> members : clsMap.values() ) { - for( Member m : members ) { - if( m instanceof AccessibleObject ) - ((AccessibleObject)m).setAccessible(true); - } - } - memberMap.put(cls,clsMap); - } - List<Member> rtn = clsMap.get(name); - if( rtn==null ) - rtn = Collections.emptyList(); - return rtn; - } - - private static synchronized List<Member> getStaticMembers(Class cls,String name) { - List<Member> staticMembers = new ArrayList<Member>(); - for( Member m : getMembers(cls,name) ) { - if( Modifier.isStatic(m.getModifiers()) ) - staticMembers.add(m); - } - return staticMembers; - } - - static final class Static implements Member { - final Class cls; - - Static(Class cls) { - this.cls = cls; - } - - @Override public String toString() { - return cls.toString(); - } - - @Override public Class<?> getDeclaringClass() { - return cls.getDeclaringClass(); - } - - @Override public String getName() { - return cls.getName(); - } - - @Override public int getModifiers() { - return cls.getModifiers(); - } - - @Override public boolean isSynthetic() { - return cls.isSynthetic(); - } - } - - public static Static getClass(LuanState luan,String name) throws LuanException { - Class cls; - try { - cls = Class.forName(name); - } catch(ClassNotFoundException e) { - try { - cls = Thread.currentThread().getContextClassLoader().loadClass(name); - } catch(ClassNotFoundException e2) { - return null; - } - } - return new Static(cls); - } -/* - public static void importClass(LuanState luan,String name) throws LuanException { - luan.currentEnvironment().put( name.substring(name.lastIndexOf('.')+1), getClass(luan,name) ); - } -*/ - static class AmbiguousJavaFunction extends LuanFunction { - private final Map<Integer,List<LuanJavaFunction>> fnMap = new HashMap<Integer,List<LuanJavaFunction>>(); - - AmbiguousJavaFunction(List<LuanJavaFunction> fns) { - for( LuanJavaFunction fn : fns ) { - Integer n = fn.getParameterTypes().length; - List<LuanJavaFunction> list = fnMap.get(n); - if( list==null ) { - list = new ArrayList<LuanJavaFunction>(); - fnMap.put(n,list); - } - list.add(fn); - } - } - - @Override public Object call(LuanState luan,Object[] args) throws LuanException { - for( LuanJavaFunction fn : fnMap.get(args.length) ) { - try { - return fn.rawCall(luan,args); - } catch(IllegalArgumentException e) {} - } - throw luan.exception("no method matched args"); - } - } - - private static class InstanceOf { - private final Object obj; - - InstanceOf(Object obj) { - this.obj = obj; - } - - public boolean instanceOf(Static st) { - return st.cls.isInstance(obj); - } - } - private static final Method instanceOf; - static { - try { - instanceOf = InstanceOf.class.getMethod("instanceOf",Static.class); - instanceOf.setAccessible(true); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - - private static class AssertClass { - private final Class cls; - - AssertClass(Class cls) { - this.cls = cls; - } - - public Object assertClass(LuanState luan,Object v) throws LuanException { - if( !cls.isInstance(v) ) { - String got = v.getClass().getSimpleName(); - String expected = cls.getSimpleName(); - throw luan.exception("bad argument #1 ("+expected+" expected, got "+got+")"); - } - return v; - } - } - private static final Method assertClass; - static { - try { - assertClass = AssertClass.class.getMethod("assertClass",LuanState.class,Object.class); - assertClass.setAccessible(true); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - - public static Object proxy(final LuanState luan,Static st,final LuanTable t,final Object base) throws LuanException { - return Proxy.newProxyInstance( - st.cls.getClassLoader(), - new Class[]{st.cls}, - new InvocationHandler() { - public Object invoke(Object proxy,Method method, Object[] args) - throws Throwable - { - if( args==null ) - args = new Object[0]; - String name = method.getName(); - Object fnObj = t.get(name); - if( fnObj==null && base!=null ) - return method.invoke(base,args); - LuanFunction fn = luan.checkFunction(fnObj); - return Luan.first(luan.call(fn,name,args)); - } - } - ); - } -}
--- a/src/luan/lib/MathLib.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -package luan.lib; - -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanException; - - -public final class MathLib { - - public static final LuanFunction LOADER = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - LuanTable module = new LuanTable(); - try { - add( module, "abs", Double.TYPE ); - add( module, "acos", Double.TYPE ); - add( module, "asin", Double.TYPE ); - add( module, "atan", Double.TYPE ); - add( module, "atan2", Double.TYPE, Double.TYPE ); - add( module, "ceil", Double.TYPE ); - add( module, "cos", Double.TYPE ); - add( module, "cosh", Double.TYPE ); - add( module, "deg", Double.TYPE ); - add( module, "exp", Double.TYPE ); - add( module, "floor", Double.TYPE ); - add( module, "log", Double.TYPE ); - add( module, "min", Double.TYPE, new double[0].getClass() ); - add( module, "max", Double.TYPE, new double[0].getClass() ); - add( module, "modf", Double.TYPE ); - module.put("pi",Math.PI); - add( module, "pow", Double.TYPE, Double.TYPE ); - add( module, "rad", Double.TYPE ); - add( module, "random" ); - add( module, "sin", Double.TYPE ); - add( module, "sinh", Double.TYPE ); - add( module, "sqrt", Double.TYPE ); - add( module, "tan", Double.TYPE ); - add( module, "tanh", Double.TYPE ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return module; - } - }; - - private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { - t.put( method, new LuanJavaFunction(MathLib.class.getMethod(method,parameterTypes),null) ); - } - - public static double abs(double x) { - return Math.abs(x); - } - - public static double acos(double x) { - return Math.acos(x); - } - - public static double asin(double x) { - return Math.asin(x); - } - - public static double atan(double x) { - return Math.atan(x); - } - - public static double atan2(double y,double x) { - return Math.atan2(y,x); - } - - public static double ceil(double x) { - return Math.ceil(x); - } - - public static double cos(double x) { - return Math.cos(x); - } - - public static double cosh(double x) { - return Math.cosh(x); - } - - public static double deg(double x) { - return Math.toDegrees(x); - } - - public static double exp(double x) { - return Math.exp(x); - } - - public static double floor(double x) { - return Math.floor(x); - } - - public static double log(double x) { - return Math.log(x); - } - - public static double min(double x,double... a) { - for( double d : a ) { - if( x > d ) - x = d; - } - return x; - } - - public static double max(double x,double... a) { - for( double d : a ) { - if( x < d ) - x = d; - } - return x; - } - - public static double[] modf(double x) { - double i = (int)x; - return new double[]{i,x-i}; - } - - public static double pow(double x,double y) { - return Math.pow(x,y); - } - - public static double rad(double x) { - return Math.toRadians(x); - } - - public static double random() { - return Math.random(); - } - - public static double sin(double x) { - return Math.sin(x); - } - - public static double sinh(double x) { - return Math.sinh(x); - } - - public static double sqrt(double x) { - return Math.sqrt(x); - } - - public static double tan(double x) { - return Math.tan(x); - } - - public static double tanh(double x) { - return Math.tanh(x); - } - -}
--- a/src/luan/lib/PackageLib.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,170 +0,0 @@ -package luan.lib; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import luan.Luan; -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanElement; -import luan.LuanException; - - -public final class PackageLib { - - private static final String jpath = "luan.lib.?Lib.LOADER"; - - public static final LuanFunction LOADER = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - LuanTable module = new LuanTable(); - module.put("loaded",luan.loaded()); - module.put("preload",luan.preload()); - module.put("path","?.luan;java:luan/modules/?.luan"); - module.put("jpath",jpath); - try { - add( module, "require", LuanState.class, String.class ); - add( module, "load_lib", String.class ); - add( module, "search_path", String.class, String.class ); - add( module, "search", LuanState.class, String.class ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - LuanTable searchers = luan.searchers(); - searchers.add(preloadSearcher); - searchers.add(fileSearcher); - searchers.add(javaSearcher); - module.put("searchers",searchers); - return module; - } - }; - - private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { - t.put( method, new LuanJavaFunction(PackageLib.class.getMethod(method,parameterTypes),null) ); - } - - public static Object require(LuanState luan,String modName) throws LuanException { - LuanTable loaded = luan.loaded(); - Object mod = loaded.get(modName); - if( mod == null ) { - Object[] a = search(luan,modName); - if( a == null ) - throw luan.exception( "module '"+modName+"' not found" ); - LuanFunction loader = (LuanFunction)a[0]; - a[0] = modName; - mod = Luan.first(luan.call(loader,"<require \""+modName+"\">",a)); - if( mod != null ) { - loaded.put(modName,mod); - } else { - mod = loaded.get(modName); - if( mod==null ) - loaded.put(modName,true); - } - } - return mod; - } - - public static Object[] search(LuanState luan,String modName) throws LuanException { - List<Object> list = null; - LuanTable searchers = (LuanTable)luan.get("Package.searchers"); - if( searchers == null ) { - list = Collections.<Object>singletonList(javaSearcher); - } else { - list = searchers.asList(); - } - for( Object s : list ) { - LuanFunction searcher = (LuanFunction)s; - Object[] a = Luan.array(luan.call(searcher,"<searcher>",new Object[]{modName})); - if( a.length >= 1 && a[0] instanceof LuanFunction ) - return a; - } - return null; - } - - public static final LuanFunction preloadSearcher = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - String modName = (String)args[0]; - return luan.preload().get(modName); - } - }; - - public static String search_path(String name,String path) { - name = name.replace('.','/'); - for( String s : path.split(";") ) { - String file = s.replaceAll("\\?",name); - if( Utils.exists(file) ) - return file; - } - return null; - } - - public static final LuanFunction fileLoader = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) throws LuanException { - String fileName = (String)args[1]; - LuanFunction fn = BasicLib.load_file(luan,fileName); - return fn.call(luan,args); - } - }; - - public static final LuanFunction fileSearcher = new LuanFunction() { - @Override public Object[] call(LuanState luan,Object[] args) { - String modName = (String)args[0]; - String path = (String)luan.get("Package.path"); - if( path==null ) - return LuanFunction.NOTHING; - String file = search_path(modName,path); - return file==null ? LuanFunction.NOTHING : new Object[]{fileLoader,file}; - } - }; - - - public static final LuanFunction javaLoader = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) throws LuanException { - try { - String objName = (String)args[1]; - LuanFunction fn = load_lib(objName); - return fn.call(luan,args); - } catch(ClassNotFoundException e) { - throw new RuntimeException(e); - } catch(NoSuchFieldException e) { - throw new RuntimeException(e); - } catch(IllegalAccessException e) { - throw new RuntimeException(e); - } - } - }; - - public static final LuanFunction javaSearcher = new LuanFunction() { - @Override public Object[] call(LuanState luan,Object[] args) { - String modName = (String)args[0]; - String path = (String)luan.get("Package.jpath"); - if( path==null ) - path = jpath; - for( String s : path.split(";") ) { - String objName = s.replaceAll("\\?",modName); - try { - load_lib(objName); // throws exception if not found - return new Object[]{javaLoader,objName}; - } catch(ClassNotFoundException e) { - } catch(NoSuchFieldException e) { - } catch(IllegalAccessException e) { - } - } - return LuanFunction.NOTHING; - } - }; - - - public static LuanFunction load_lib(String path) - throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException - { - int i = path.lastIndexOf('.'); - String clsPath = path.substring(0,i); - String fld = path.substring(i+1); - Class cls = Class.forName(clsPath); - return (LuanFunction)cls.getField(fld).get(null); - } - -}
--- a/src/luan/lib/PickleClient.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -package luan.lib; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import luan.Luan; -import luan.LuanState; -import luan.LuanException; -import luan.LuanTable; -import luan.LuanJavaFunction; -import luan.LuanFunction; - - -public final class PickleClient { - - private final PickleCon con; - private final LuanFunction _reversed_pickle; - - PickleClient(LuanState luan,DataInputStream in,DataOutputStream out) { - this(new PickleCon(luan,in,out)); - } - - PickleClient(PickleCon con) { - this.con = con; - try { - this._reversed_pickle = new LuanJavaFunction( - PickleClient.class.getMethod( "_reversed_pickle" ), this - ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - public Object _reversed_pickle() throws LuanException, IOException { - new PickleServer(con).run(); - return con.read(); - } - - public Object call(Object... args) throws LuanException, IOException { - con.write(args); - Object[] result; - con.ioModule.put("_reversed_pickle",_reversed_pickle); - try { - result = Luan.array(con.read()); - } finally { - con.ioModule.put("_reversed_pickle",null); - } - boolean ok = (boolean)result[0]; - if( ok ) { - Object[] rtn = new Object[result.length-1]; - System.arraycopy(result,1,rtn,0,rtn.length); - return rtn; - } else { - String msg = (String)result[1]; - String src = (String)result[2]; - throw con.luan.exception( - msg + "\n" - + "in:\n" - + "------------------\n" - + formatCode(src) + "\n" - + "------------------\n" - ); - } - } - - LuanTable table() { - LuanTable tbl = new LuanTable(); - try { - tbl.put( "pickle", new LuanJavaFunction( - PickleCon.class.getMethod( "pickle", Object.class ), con - ) ); - tbl.put( "call", new LuanJavaFunction( - PickleClient.class.getMethod( "call", new Object[0].getClass() ), this - ) ); - tbl.put( "close", new LuanJavaFunction( - PickleCon.class.getMethod( "close" ), con - ) ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return tbl; - } - - - public static String formatCode(String s) { - StringBuilder buf = new StringBuilder(); - int line = 1; - int i = 0; - int i2 = 0; - while( i2 != -1 ) { - buf.append( line++ ); - buf.append( '\t' ); - i2 = s.indexOf('\n',i); - String lineStr = i2 == -1 ? s.substring(i) : s.substring(i,i2+1); - int j; - for( j=0; j<lineStr.length() && lineStr.charAt(j)=='\t'; j++ ) { - buf.append( " " ); - } - buf.append( lineStr.substring(j) ); - i = i2 + 1; - } - return buf.toString(); - } - - -}
--- a/src/luan/lib/PickleCon.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -package luan.lib; - -import java.io.OutputStream; -import java.io.BufferedOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Set; -import java.util.IdentityHashMap; -import java.util.Collections; -import java.util.Map; -import java.util.List; -import java.util.ArrayList; -import luan.Luan; -import luan.LuanTable; -import luan.LuanState; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanException; - - -public final class PickleCon { - final LuanState luan; - private final DataInputStream in; - private final LuanFunction _read_binary; - final LuanTable ioModule; - private final DataOutputStream out; - private final List<byte[]> binaries = new ArrayList<byte[]>(); - String src; - private final LuanTable env = new LuanTable(); - - PickleCon(LuanState luan,DataInputStream in,DataOutputStream out) { - this.in = in; - this.luan = luan; - try { - this._read_binary = new LuanJavaFunction( - PickleCon.class.getMethod( "_read_binary", Integer.TYPE ), this - ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - this.ioModule = (LuanTable)luan.loaded().get("Io"); - - this.out = out; - } - - public byte[] _read_binary(int size) throws IOException, LuanException { - byte[] a = new byte[size]; - int i = 0; - while( i < size ) { - int n = in.read(a,i,size-i); - if( n == -1 ) - throw luan.exception( "end of stream" ); - i += n; - } - return a; - } - - public Object read() throws IOException, LuanException { - ioModule.put("_read_binary",_read_binary); - try { - src = in.readUTF(); - LuanFunction fn = BasicLib.load(luan,src,"pickle-reader",env,false); - return luan.call(fn); - } finally { - ioModule.put("_binaries",null); - ioModule.put("_read_binary",null); - } - } - - public String pickle(Object obj) throws LuanException { - if( obj == null ) - return "nil"; - if( obj instanceof Boolean ) - return Luan.toString((Boolean)obj); - if( obj instanceof Number ) - return Luan.toString((Number)obj); - if( obj instanceof String ) - return "\"" + Luan.stringEncode((String)obj) + "\""; - if( obj instanceof LuanTable ) - return pickle( (LuanTable)obj, Collections.newSetFromMap(new IdentityHashMap<LuanTable,Boolean>()) ); - if( obj instanceof byte[] ) { - byte[] a = (byte[])obj; - binaries.add(a); - return "Io._binaries[" + binaries.size() + "]"; - } - throw luan.exception( "invalid type: " + obj.getClass() ); - } - - private String pickle(Object obj,Set<LuanTable> set) throws LuanException { - return obj instanceof LuanTable ? pickle((LuanTable)obj,set) : pickle(obj); - } - - private String pickle(LuanTable tbl,Set<LuanTable> set) throws LuanException { - if( !set.add(tbl) ) { - throw luan.exception( "circular reference in table" ); - } - StringBuilder sb = new StringBuilder(); - sb.append( "{" ); - for( Map.Entry<Object,Object> entry : tbl ) { - sb.append( "[" ); - sb.append( pickle(entry.getKey(),set) ); - sb.append( "]=" ); - sb.append( pickle(entry.getValue(),set) ); - sb.append( ", " ); - } - sb.append( "}" ); - return sb.toString(); - } - - public void write(Object... args) throws LuanException, IOException { - StringBuilder sb = new StringBuilder(); - if( !binaries.isEmpty() ) { - sb.append( "Io._binaries = {}\n" ); - for( byte[] a : binaries ) { - sb.append( "Io._binaries[#Io._binaries+1] = Io._read_binary(" + a.length + ")\n" ); - } - } - for( Object obj : args ) { - sb.append( luan.toString(obj) ); - } - out.writeUTF( sb.toString() ); - for( byte[] a : binaries ) { - out.write(a); - } - out.flush(); - binaries.clear(); - } - - public void close() throws IOException { - in.close(); - out.close(); - } -}
--- a/src/luan/lib/PickleServer.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -package luan.lib; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.EOFException; -import java.util.List; -import java.util.ArrayList; -import luan.Luan; -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanException; - - -public final class PickleServer { - - private final PickleCon con; - private boolean isRunning; - - PickleServer(LuanState luan,DataInputStream in,DataOutputStream out) { - this(new PickleCon(luan,in,out)); - } - - PickleServer(PickleCon con) { - this.con = con; - } - - void next() throws IOException { - try { - List<String> list = new ArrayList<String>(); - try { - Object[] result = Luan.array(con.read()); - list.add( "return true" ); - for( Object obj : result ) { - list.add( ", " ); - list.add( con.pickle(obj) ); - } - } catch(LuanException e) { -// System.out.println(e); -//e.printStackTrace(); - list.add( "return false, " ); - list.add( con.pickle(e.getMessage()) ); - list.add( ", " ); - list.add( con.pickle(con.src) ); - } - list.add( "\n" ); - con.write( list.toArray() ); - } catch(LuanException e2) { - throw new RuntimeException(e2); - } - } - - public void run() { - LuanTable ioModule = con.ioModule; - Object old_reverse_pickle = ioModule.get("reverse_pickle"); - Object old_unreverse_pickle = ioModule.get("_unreverse_pickle"); - try { - try { - ioModule.put("reverse_pickle", new LuanJavaFunction( - PickleServer.class.getMethod( "reverse_pickle", LuanFunction.class ), this - ) ); - ioModule.put("_unreverse_pickle", new LuanJavaFunction( - PickleServer.class.getMethod( "_unreverse_pickle" ), this - ) ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - isRunning = true; - try { - while( isRunning ) { - next(); - } - } catch(EOFException e) { - // done - } catch(IOException e) { - e.printStackTrace(); - } - if( isRunning ) { - try { - con.close(); - } catch(IOException e) { - throw new RuntimeException(e); - } - } - } finally { - ioModule.put("reverse_pickle",old_reverse_pickle); - ioModule.put("_unreverse_pickle",old_unreverse_pickle); - } - } - - public void reverse_pickle(LuanFunction fn) throws IOException, LuanException { - try { - con.write( "return Io._reversed_pickle()\n" ); - } catch(LuanException e) { - throw new RuntimeException(e); - } - PickleClient pc = new PickleClient(con); - try { - con.luan.call(fn,new Object[]{pc.table()}); - } finally { - try { - pc.call( "Io._unreverse_pickle()\n" ); - } catch(LuanException e) { - throw new RuntimeException(e); - } - } - } - - public void _unreverse_pickle() { - isRunning = false; - } - -}
--- a/src/luan/lib/StringLib.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -package luan.lib; - -import java.util.regex.Pattern; -import java.util.regex.Matcher; -import luan.Luan; -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanElement; -import luan.LuanException; -import luan.MetatableGetter; - - -public final class StringLib { - - public static final LuanFunction LOADER = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - luan.addMetatableGetter(mg); - LuanTable module = new LuanTable(); - try { - add( module, "to_binary", String.class ); - add( module, "to_integers", String.class ); - add( module, "from_integers", new int[0].getClass() ); - add( module, "find", String.class, String.class, Integer.class, Boolean.class ); - add( module, "format", String.class, new Object[0].getClass() ); - add( module, "gmatch", String.class, String.class ); - add( module, "gsub", LuanState.class, String.class, String.class, Object.class, Integer.class ); - add( module, "len", String.class ); - add( module, "lower", String.class ); - add( module, "match", String.class, String.class, Integer.class ); - add( module, "rep", String.class, Integer.TYPE, String.class ); - add( module, "reverse", String.class ); - add( module, "sub", String.class, Integer.TYPE, Integer.class ); - add( module, "upper", String.class ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return module; - } - }; - - private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { - t.put( method, new LuanJavaFunction(StringLib.class.getMethod(method,parameterTypes),null) ); - } - - private static final LuanTable mt = new LuanTable(); - static { - try { - add( mt, "__index", LuanState.class, String.class, Object.class ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - private static final MetatableGetter mg = new MetatableGetter() { - public LuanTable getMetatable(Object obj) { - return obj instanceof String ? mt : null; - } - }; - - public static Object __index(LuanState luan,final String s,Object key) throws LuanException { - LuanTable mod = (LuanTable)luan.loaded().get("String"); - if( mod!=null ) { - Object obj = mod.get(key); - if( obj instanceof LuanFunction ) { - final LuanFunction fn = (LuanFunction)obj; - return new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) throws LuanException { - Object[] a = new Object[args.length+1]; - a[0] = s; - System.arraycopy(args,0,a,1,args.length); - return fn.call(luan,a); - } - }; - } - } - if( luan.loaded().get("Java") != null ) - return JavaLib.__index(luan,s,key); - return null; - } - - static int start(String s,int i) { - return i==0 ? 0 : i > 0 ? i - 1 : s.length() + i; - } - - static int start(String s,Integer i,int dflt) { - return i==null ? dflt : start(s,i); - } - - static int end(String s,int i) { - return i==0 ? 0 : i > 0 ? i : s.length() + i + 1; - } - - static int end(String s,Integer i,int dflt) { - return i==null ? dflt : end(s,i); - } - - public static byte[] to_binary(String s) { - return s.getBytes(); - } - - public static int[] to_integers(String s) { - char[] a = s.toCharArray(); - int[] chars = new int[a.length]; - for( int i=0; i<a.length; i++ ) { - chars[i] = a[i]; - } - return chars; - } - - public static String from_integers(int... chars) { - char[] a = new char[chars.length]; - for( int i=0; i<chars.length; i++ ) { - a[i] = (char)chars[i]; - } - return new String(a); - } - - public static int len(String s) { - return s.length(); - } - - public static String lower(String s) { - return s.toLowerCase(); - } - - public static String upper(String s) { - return s.toUpperCase(); - } - - public static String reverse(String s) { - return new StringBuilder(s).reverse().toString(); - } - - public static String rep(String s,int n,String sep) { - if( n < 1 ) - return ""; - StringBuilder buf = new StringBuilder(s); - while( --n > 0 ) { - if( sep != null ) - buf.append(sep); - buf.append(s); - } - return buf.toString(); - } - - public static String sub(String s,int i,Integer j) { - int start = start(s,i); - int end = end(s,j,s.length()); - return s.substring(start,end); - } - - public static int[] find(String s,String pattern,Integer init,Boolean plain) { - int start = start(s,init,0); - if( Boolean.TRUE.equals(plain) ) { - int i = s.indexOf(pattern,start); - return i == -1 ? null : new int[]{i+1,i+pattern.length()}; - } - Matcher m = Pattern.compile(pattern).matcher(s); - return m.find(start) ? new int[]{m.start()+1,m.end()} : null; - } - - public static String[] match(String s,String pattern,Integer init) { - int start = start(s,init,0); - Matcher m = Pattern.compile(pattern).matcher(s); - if( !m.find(start) ) - return null; - final int n = m.groupCount(); - if( n == 0 ) - return new String[]{m.group()}; - String[] rtn = new String[n]; - for( int i=0; i<n; i++ ) { - rtn[i] = m.group(i+1); - } - return rtn; - } - - public static LuanFunction gmatch(String s,String pattern) { - final Matcher m = Pattern.compile(pattern).matcher(s); - return new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - if( !m.find() ) - return null; - final int n = m.groupCount(); - if( n == 0 ) - return m.group(); - String[] rtn = new String[n]; - for( int i=0; i<n; i++ ) { - rtn[i] = m.group(i+1); - } - return rtn; - } - }; - } - - public static Object[] gsub(LuanState luan,String s,String pattern,Object repl,Integer n) throws LuanException { - int max = n==null ? Integer.MAX_VALUE : n; - final Matcher m = Pattern.compile(pattern).matcher(s); - if( repl instanceof String ) { - String replacement = (String)repl; - int i = 0; - StringBuffer sb = new StringBuffer(); - while( i<max && m.find() ) { - m.appendReplacement(sb,replacement); - i++; - } - m.appendTail(sb); - return new Object[]{ sb.toString(), i }; - } - if( repl instanceof LuanTable ) { - LuanTable t = (LuanTable)repl; - int i = 0; - StringBuffer sb = new StringBuffer(); - while( i<max && m.find() ) { - String match = m.groupCount()==0 ? m.group() : m.group(1); - Object val = t.get(match); - if( Luan.toBoolean(val) ) { - String replacement = Luan.asString(val); - if( replacement==null ) - throw luan.exception( "invalid replacement value (a "+Luan.type(val)+")" ); - m.appendReplacement(sb,replacement); - } - i++; - } - m.appendTail(sb); - return new Object[]{ sb.toString(), i }; - } - if( repl instanceof LuanFunction ) { - LuanFunction fn = (LuanFunction)repl; - int i = 0; - StringBuffer sb = new StringBuffer(); - while( i<max && m.find() ) { - Object[] args; - final int count = m.groupCount(); - if( count == 0 ) { - args = new Object[]{m.group()}; - } else { - args = new Object[count]; - for( int j=0; j<count; j++ ) { - args[j] = m.group(j); - } - } - Object val = Luan.first( luan.call(fn,"repl-arg",args) ); - if( Luan.toBoolean(val) ) { - String replacement = Luan.asString(val); - if( replacement==null ) - throw luan.exception( "invalid replacement value (a "+Luan.type(val)+")" ); - m.appendReplacement(sb,replacement); - } - i++; - } - m.appendTail(sb); - return new Object[]{ sb.toString(), i }; - } - throw luan.exception( "bad argument #3 to 'gsub' (string/function/table expected)" ); - } - - // note - String.format() is too stupid to convert between ints and floats. - public static String format(String format,Object... args) { - return String.format(format,args); - } - -}
--- a/src/luan/lib/TableLib.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -package luan.lib; - -import java.util.Comparator; -import java.util.List; -import java.util.ArrayList; -import java.util.Arrays; -import luan.Luan; -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanElement; -import luan.LuanException; -import luan.LuanRuntimeException; - - -public final class TableLib { - - public static final LuanFunction LOADER = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - LuanTable module = new LuanTable(); - try { - add( module, "concat", LuanState.class, LuanTable.class, String.class, Integer.class, Integer.class ); - add( module, "insert", LuanState.class, LuanTable.class, Integer.TYPE, Object.class ); - add( module, "pack", new Object[0].getClass() ); - add( module, "remove", LuanState.class, LuanTable.class, Integer.TYPE ); - add( module, "sort", LuanState.class, LuanTable.class, LuanFunction.class ); - add( module, "sub_list", LuanTable.class, Integer.TYPE, Integer.TYPE ); - add( module, "unpack", LuanTable.class, Integer.class, Integer.class ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return module; - } - }; - - private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { - t.put( method, new LuanJavaFunction(TableLib.class.getMethod(method,parameterTypes),null) ); - } - - public static String concat(LuanState luan,LuanTable list,String sep,Integer i,Integer j) throws LuanException { - int first = i==null ? 1 : i; - int last = j==null ? list.length() : j; - StringBuilder buf = new StringBuilder(); - for( int k=first; k<=last; k++ ) { - Object val = list.get(k); - if( val==null ) - break; - if( sep!=null && k > first ) - buf.append(sep); - String s = Luan.asString(val); - if( s==null ) - throw luan.exception( "invalid value ("+Luan.type(val)+") at index "+k+" in table for 'concat'" ); - buf.append(val); - } - return buf.toString(); - } - - public static void insert(LuanState luan,LuanTable list,int pos,Object value) throws LuanException { - try { - list.insert(pos,value); - } catch(IndexOutOfBoundsException e) { - throw luan.exception(e); - } - } - - public static Object remove(LuanState luan,LuanTable list,int pos) throws LuanException { - try { - return list.remove(pos); - } catch(IndexOutOfBoundsException e) { - throw luan.exception(e); - } - } - - private static interface LessThan { - public boolean isLessThan(Object o1,Object o2); - } - - public static void sort(final LuanState luan,LuanTable list,final LuanFunction comp) throws LuanException { - final LessThan lt; - if( comp==null ) { - lt = new LessThan() { - public boolean isLessThan(Object o1,Object o2) { - try { - return luan.isLessThan(o1,o2); - } catch(LuanException e) { - throw new LuanRuntimeException(e); - } - } - }; - } else { - lt = new LessThan() { - public boolean isLessThan(Object o1,Object o2) { - try { - return Luan.toBoolean(Luan.first(luan.call(comp,"comp-arg",new Object[]{o1,o2}))); - } catch(LuanException e) { - throw new LuanRuntimeException(e); - } - } - }; - } - try { - list.sort( new Comparator<Object>() { - public int compare(Object o1,Object o2) { - return lt.isLessThan(o1,o2) ? -1 : lt.isLessThan(o2,o1) ? 1 : 0; - } - } ); - } catch(LuanRuntimeException e) { - throw (LuanException)e.getCause(); - } - } - - public static LuanTable pack(Object... args) { - return new LuanTable(new ArrayList<Object>(Arrays.asList(args))); - } - - public static Object[] unpack(LuanTable tbl,Integer iFrom,Integer iTo) { - int from = iFrom!=null ? iFrom : 1; - int to = iTo!=null ? iTo : tbl.length(); - List<Object> list = new ArrayList<Object>(); - for( int i=from; i<=to; i++ ) { - list.add( tbl.get(i) ); - } - return list.toArray(); - } - - public static LuanTable sub_list(LuanTable list,int from,int to) { - return list.subList(from,to); - } - -}
--- a/src/luan/lib/ThreadLib.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -package luan.lib; - -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import luan.LuanState; -import luan.LuanFunction; -import luan.LuanTable; -import luan.LuanJavaFunction; -import luan.LuanException; -import luan.DeepCloner; - - -public final class ThreadLib { - - public static final LuanFunction LOADER = new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) { - LuanTable module = new LuanTable(); - try { - add( module, "fork", LuanState.class, LuanFunction.class, new Object[0].getClass() ); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - return module; - } - }; - - private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { - t.put( method, new LuanJavaFunction(ThreadLib.class.getMethod(method,parameterTypes),null) ); - } - - private static final Executor exec = Executors.newCachedThreadPool(); - - public static void fork(LuanState luan,LuanFunction fn,Object... args) { - DeepCloner cloner = new DeepCloner(); - final LuanState newLuan = cloner.deepClone(luan); - final LuanFunction newFn = cloner.get(fn); - final Object[] newArgs = cloner.deepClone(args); - exec.execute(new Runnable(){public void run() { - try { - newLuan.call(newFn,"<forked>",newArgs); - } catch(LuanException e) { - e.printStackTrace(); - } - }}); - } - -}
--- a/src/luan/lib/Utils.java Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -package luan.lib; - -import java.io.Reader; -import java.io.IOException; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.File; -import java.net.URL; -import java.net.MalformedURLException; -import luan.LuanState; -import luan.LuanException; - - -public final class Utils { - private Utils() {} // never - - static final int bufSize = 8192; - - public static void checkNotNull(LuanState luan,Object v,String expected) throws LuanException { - if( v == null ) - throw luan.exception("bad argument #1 ("+expected+" expected, got nil)"); - } - - public static String readAll(Reader in) - throws IOException - { - char[] a = new char[bufSize]; - StringBuilder buf = new StringBuilder(); - int n; - while( (n=in.read(a)) != -1 ) { - buf.append(a,0,n); - } - return buf.toString(); - } - - public static void copyAll(InputStream in,OutputStream out) - throws IOException - { - byte[] a = new byte[bufSize]; - int n; - while( (n=in.read(a)) != -1 ) { - out.write(a,0,n); - } - } - - public static byte[] readAll(InputStream in) - throws IOException - { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - copyAll(in,out); - return out.toByteArray(); - } - - public static boolean exists(File file) { - try { - return file.exists() && file.getName().equals(file.getCanonicalFile().getName()); - } catch(IOException e) { - throw new RuntimeException(e); - } - } - - public static boolean isFile(String path) { - return exists(new File(path)); - } - - public static String toUrl(String path) { - if( path.indexOf(':') == -1 ) - return null; - if( path.startsWith("java:") ) { - path = path.substring(5); - URL url = ClassLoader.getSystemResource(path); - return url==null ? null : url.toString(); - } - try { - new URL(path); - return path; - } catch(MalformedURLException e) {} - return null; - } - - public static boolean exists(String path) { - return isFile(path) || toUrl(path)!=null; - } -}
--- a/src/luan/lib/init.luan Sun Jun 22 04:17:38 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -function Package.global(module,fn_name) - local function fn(...) - return module[fn_name](...) - end - _G[fn_name] = fn - return fn -end - -local require = Package.global(Package,"require") - -function Package.global_import(name) - local mod = require(name) - _G[name] = mod - return mod -end - -local Basic = Package.global_import("Basic","luan.lib.BasicLib.LOADER") -Package.global(Basic,"assert") -Package.global(Basic,"assert_boolean") -Package.global(Basic,"assert_nil") -Package.global(Basic,"assert_number") -Package.global(Basic,"assert_string") -Package.global(Basic,"assert_table") -Package.global(Basic,"do_file") -Package.global(Basic,"error") -Package.global(Basic,"get_metatable") -Package.global(Basic,"ipairs") -local load = Package.global(Basic,"load") -Package.global(Basic,"load_file") -Package.global(Basic,"pairs") -Package.global(Basic,"range") -Package.global(Basic,"raw_equal") -Package.global(Basic,"raw_get") -Package.global(Basic,"raw_len") -Package.global(Basic,"raw_set") -Package.global(Basic,"repr") -Package.global(Basic,"set_metatable") -Package.global(Basic,"to_number") -local to_string = Package.global(Basic,"to_string") -Package.global(Basic,"type") - -local String = Package.global_import("String","luan.lib.StringLib.LOADER") - --- improved global_import -function Package.global_import(name) - local short = name.match("\.([^.]+)$") or name - local mod = require(name) - _G[short] = mod - return mod -end - -local Table = Package.global_import("Table","luan.lib.TableLib.LOADER") -local Io = Package.global_import("Io","luan.lib.IoLib.LOADER") -Package.global_import("Math","luan.lib.MathLib.LOADER") -Package.global_import("Html","luan.lib.HtmlLib.LOADER") -Package.global_import("Thread","luan.lib.ThreadLib.LOADER") -Package.global_import("Binary","luan.lib.BinaryLib.LOADER") - - -function Io.print_to(out,...) - local list = {} - for _,v in Basic.values(...) do - list[#list+1] = to_string(v) - list[#list+1] = '\t' - end - if #list == 0 then - out.write( '\n' ) - else - list[#list] = '\n' - out.write( Table.unpack(list) ) - end -end - -function Basic.print(...) - Io.print_to(Io.stdout,...) -end -local print = Package.global(Basic,"print") - -local Debug = {} -Package.loaded.Debug = Debug -_G.Debug = Debug - -function Debug.print_if_something(...) - if Table.pack(...).n > 0 then - print(...) - end -end - -function Debug.debug(prompt) - prompt = prompt or "luan_debug> " - local function console() - return Io.read_console_line(prompt) - end - local env = {} - for line in console do - try - local fn = load(line,"stdin",env,true) - Debug.print_if_something( fn() ) - catch e do - print(e) - end - end -end - - --- import modules -Package.global_import("Reactionary")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/BasicLib.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,222 @@ +package luan.modules; + +import java.io.File; +import java.io.InputStreamReader; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.Iterator; +import java.util.Map; +import java.util.List; +import java.util.ArrayList; +import luan.Luan; +import luan.LuanState; +import luan.LuanTable; +import luan.LuanFunction; +import luan.LuanJavaFunction; +import luan.LuanException; +import luan.LuanSource; +import luan.LuanElement; +import luan.impl.LuanCompiler; + + +public final class BasicLib { + + public static final LuanFunction LOADER = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + LuanTable module = new LuanTable(); + try { + module.put( "assert", new LuanJavaFunction(BasicLib.class.getMethod("assert_",LuanState.class,Object.class,String.class),null) ); + add( module, "assert_boolean", LuanState.class, Boolean.TYPE ); + add( module, "assert_nil", LuanState.class, Object.class ); + add( module, "assert_number", LuanState.class, Number.class ); + add( module, "assert_string", LuanState.class, String.class ); + add( module, "assert_table", LuanState.class, LuanTable.class ); + add( module, "do_file", LuanState.class, String.class ); + add( module, "error", LuanState.class, Object.class ); + add( module, "get_metatable", LuanState.class, Object.class ); + add( module, "ipairs", LuanState.class, LuanTable.class ); + add( module, "load", LuanState.class, String.class, String.class, LuanTable.class, Boolean.class ); + add( module, "load_file", LuanState.class, String.class ); + add( module, "pairs", LuanState.class, LuanTable.class ); + add( module, "range", LuanState.class, Double.TYPE, Double.TYPE, Double.class ); + add( module, "raw_equal", Object.class, Object.class ); + add( module, "raw_get", LuanTable.class, Object.class ); + add( module, "raw_len", LuanState.class, Object.class ); + add( module, "raw_set", LuanTable.class, Object.class, Object.class ); + add( module, "repr", LuanState.class, Object.class ); + add( module, "set_metatable", LuanTable.class, LuanTable.class ); + add( module, "to_number", Object.class, Integer.class ); + add( module, "to_string", LuanState.class, Object.class ); + add( module, "type", Object.class ); + add( module, "values", new Object[0].getClass() ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return module; + } + }; + + private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { + t.put( method, new LuanJavaFunction(BasicLib.class.getMethod(method,parameterTypes),null) ); + } + + public static String type(Object obj) { + return Luan.type(obj); + } + + public static LuanFunction load(LuanState luan,String text,String sourceName,LuanTable env,Boolean allowExpr) + throws LuanException + { + if( allowExpr==null ) + allowExpr = false; + return LuanCompiler.compile(luan,new LuanSource(sourceName,text),env,allowExpr); + } + + public static LuanFunction load_file(LuanState luan,String fileName) throws LuanException { + try { + String src = fileName==null ? Utils.readAll(new InputStreamReader(System.in)) : IoLib.luanIo(luan,fileName).read_text(); + return load(luan,src,fileName,null,false); + } catch(IOException e) { + throw luan.exception(e); + } + } + + public static Object do_file(LuanState luan,String fileName) throws LuanException { + LuanFunction fn = load_file(luan,fileName); + return luan.call(fn); + } + + private static LuanFunction pairs(final Iterator<Map.Entry<Object,Object>> iter) { + return new LuanFunction() { + @Override public Object[] call(LuanState luan,Object[] args) { + if( !iter.hasNext() ) + return LuanFunction.NOTHING; + Map.Entry<Object,Object> entry = iter.next(); + return new Object[]{entry.getKey(),entry.getValue()}; + } + }; + } + + public static LuanFunction pairs(LuanState luan,LuanTable t) throws LuanException { + Utils.checkNotNull(luan,t,"table"); + return pairs( t.iterator() ); + } + + public static LuanFunction ipairs(LuanState luan,LuanTable t) throws LuanException { + Utils.checkNotNull(luan,t,"table"); + return pairs( t.listIterator() ); + } + + public static LuanTable get_metatable(LuanState luan,Object obj) { + return luan.getMetatable(obj); + } + + public static LuanTable set_metatable(LuanTable table,LuanTable metatable) { + table.setMetatable(metatable); + return table; + } + + public static boolean raw_equal(Object v1,Object v2) { + return v1 == v2 || v1 != null && v1.equals(v2); + } + + public static Object raw_get(LuanTable table,Object index) { + return table.get(index); + } + + public static LuanTable raw_set(LuanTable table,Object index,Object value) { + table.put(index,value); + return table; + } + + public static int raw_len(LuanState luan,Object v) throws LuanException { + if( v instanceof String ) { + String s = (String)v; + return s.length(); + } + if( v instanceof LuanTable ) { + LuanTable t = (LuanTable)v; + return t.length(); + } + throw luan.exception( "bad argument #1 to 'raw_len' (table or string expected)" ); + } + + public static Number to_number(Object e,Integer base) { + return Luan.toNumber(e,base); + } + + public static String to_string(LuanState luan,Object v) throws LuanException { + return luan.toString(v); + } + + public static void error(LuanState luan,Object msg) throws LuanException { + throw luan.exception(msg); + } + + public static Object assert_(LuanState luan,Object v,String msg) throws LuanException { + if( Luan.toBoolean(v) ) + return v; + if( msg == null ) + msg = "assertion failed!"; + throw luan.exception( msg ); + } + + public static String assert_string(LuanState luan,String v) throws LuanException { + Utils.checkNotNull(luan,v,"string"); + return v; + } + + public static Number assert_number(LuanState luan,Number v) throws LuanException { + Utils.checkNotNull(luan,v,"number"); + return v; + } + + public static LuanTable assert_table(LuanState luan,LuanTable v) throws LuanException { + Utils.checkNotNull(luan,v,"table"); + return v; + } + + public static boolean assert_boolean(LuanState luan,boolean v) throws LuanException { + return v; + } + + public static Object assert_nil(LuanState luan,Object v) throws LuanException { + if( v != null ) + throw luan.exception("bad argument #1 (nil expected, got "+Luan.type(v)+")"); + return v; + } + + public static String repr(LuanState luan,Object v) throws LuanException { + return luan.repr(v); + } + + public static LuanFunction range(LuanState luan,final double from,final double to,Double stepV) throws LuanException { + final double step = stepV==null ? 1.0 : stepV; + if( step == 0.0 ) + throw luan.exception("bad argument #3 (step may not be zero)"); + return new LuanFunction() { + double v = from; + + @Override public Object call(LuanState luan,Object[] args) { + if( step > 0.0 && v > to || step < 0.0 && v < to ) + return LuanFunction.NOTHING; + double rtn = v; + v += step; + return rtn; + } + }; + } + + public static LuanFunction values(final Object... args) throws LuanException { + return new LuanFunction() { + int i = 0; + + @Override public Object call(LuanState luan,Object[] unused) { + if( ++i > args.length ) + return LuanFunction.NOTHING; + return new Object[]{i,args[i-1]}; + } + }; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/BinaryLib.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,32 @@ +package luan.modules; + +import luan.LuanState; +import luan.LuanTable; +import luan.LuanFunction; +import luan.LuanJavaFunction; +import luan.LuanException; + + +public final class BinaryLib { + + public static final LuanFunction LOADER = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + LuanTable module = new LuanTable(); + try { + add( module, "to_string", new byte[0].getClass() ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return module; + } + }; + + private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { + t.put( method, new LuanJavaFunction(BinaryLib.class.getMethod(method,parameterTypes),null) ); + } + + public static String to_string(byte[] bytes) { + return new String(bytes); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/HtmlLib.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,53 @@ +package luan.modules; + +import luan.LuanState; +import luan.LuanTable; +import luan.LuanFunction; +import luan.LuanJavaFunction; +import luan.LuanException; + + +public final class HtmlLib { + + public static final LuanFunction LOADER = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + LuanTable module = new LuanTable(); + try { + add( module, "encode", String.class ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return module; + } + }; + + private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { + t.put( method, new LuanJavaFunction(HtmlLib.class.getMethod(method,parameterTypes),null) ); + } + + public static String encode(String s) { + char[] a = s.toCharArray(); + StringBuilder buf = new StringBuilder(); + for( int i=0; i<a.length; i++ ) { + char c = a[i]; + switch(c) { + case '&': + buf.append("&"); + break; + case '<': + buf.append("<"); + break; + case '>': + buf.append(">"); + break; + case '"': + buf.append("""); + break; + default: + buf.append(c); + } + } + return buf.toString(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/HttpLib.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,285 @@ +package luan.modules; + +import java.io.PrintWriter; +import java.io.IOException; +import java.util.Map; +import java.util.Set; +import java.util.Arrays; +import java.util.Enumeration; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import luan.Luan; +import luan.LuanState; +import luan.LuanFunction; +import luan.LuanElement; +import luan.LuanException; +import luan.LuanTable; +import luan.LuanJavaFunction; +import luan.LuanExitException; +import luan.DeepCloner; + + +public final class HttpLib { + + public static final LuanFunction LOADER = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + return new LuanTable(); // starts empty + } + }; + + public static void service(LuanState luan,HttpServletRequest request,HttpServletResponse response,String modName) + throws LuanException + { + LuanFunction fn; + synchronized(luan) { + Object mod = PackageLib.require(luan,modName); + if( !(mod instanceof LuanTable) ) + throw luan.exception( "module '"+modName+"' must return a table" ); + LuanTable tbl = (LuanTable)mod; + if( Luan.toBoolean( tbl.get("per_session") ) ) { + HttpSession session = request.getSession(); + LuanState sessionLuan = (LuanState)session.getValue("luan"); + if( sessionLuan!=null ) { + luan = sessionLuan; + } else { + DeepCloner cloner = new DeepCloner(); + luan = cloner.deepClone(luan); + session.putValue("luan",luan); + } + tbl = (LuanTable)PackageLib.require(luan,modName); + fn = (LuanFunction)tbl.get("page"); + } else { + fn = (LuanFunction)tbl.get("page"); + if( fn == null ) + throw luan.exception( "function 'page' is not defined" ); + DeepCloner cloner = new DeepCloner(); + luan = cloner.deepClone(luan); + fn = cloner.get(fn); + } + } + + LuanTable module = (LuanTable)luan.loaded().get("Http"); + if( module == null ) + throw luan.exception( "module 'Http' not defined" ); + HttpLib lib = new HttpLib(request,response); + try { + module.put( "request", lib.requestTable() ); + module.put( "response", lib.responseTable() ); +/* + module.put( "write", new LuanJavaFunction( + HttpLib.class.getMethod( "text_write", LuanState.class, new Object[0].getClass() ), lib + ) ); +*/ + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + + luan.call(fn,"<http>"); + } + + + + private final HttpServletRequest request; + private final HttpServletResponse response; +// private PrintWriter writer = null; +// private ServletOutputStream sos = null; + + private HttpLib(HttpServletRequest request,HttpServletResponse response) { + this.request = request; + this.response = response; + } + + private LuanTable requestTable() throws NoSuchMethodException { + LuanTable req = new LuanTable(); + req.put("java",request); + req.put( "get_attribute", new LuanJavaFunction(HttpServletRequest.class.getMethod("getAttribute",String.class),request) ); + req.put( "set_attribute", new LuanJavaFunction(HttpServletRequest.class.getMethod("setAttribute",String.class,Object.class),request) ); + req.put( "get_parameter", new LuanJavaFunction(HttpServletRequest.class.getMethod("getParameter",String.class),request) ); + req.put( "get_parameter_values", new LuanJavaFunction(HttpServletRequest.class.getMethod("getParameterValues",String.class),request) ); + req.put( "get_header", new LuanJavaFunction(HttpServletRequest.class.getMethod("getHeader",String.class),request) ); + add( req, "get_cookie_value", String.class ); + req.put( "method", new LuanJavaFunction(HttpServletRequest.class.getMethod("getMethod"),request) ); + req.put( "servlet_path", new LuanJavaFunction(HttpServletRequest.class.getMethod("getServletPath"),request) ); + req.put( "server_name", new LuanJavaFunction(HttpServletRequest.class.getMethod("getServerName"),request) ); + add( req, "current_url" ); + req.put( "remote_address", new LuanJavaFunction(HttpServletRequest.class.getMethod("getRemoteAddr"),request) ); + add( req, "get_session_attribute", String.class ); + add( req, "set_session_attribute", String.class, Object.class ); + return req; + } + + private LuanTable responseTable() throws NoSuchMethodException { + LuanTable resp = new LuanTable(); + resp.put("java",response); + add( resp, "send_redirect", String.class ); + add( resp, "send_error", Integer.TYPE, String.class ); + resp.put( "contains_header", new LuanJavaFunction(HttpServletResponse.class.getMethod("containsHeader",String.class),response) ); + resp.put( "set_header", new LuanJavaFunction(HttpServletResponse.class.getMethod("setHeader",String.class,String.class),response) ); + add( resp, "set_cookie", String.class, String.class, Boolean.TYPE, String.class ); + add( resp, "remove_cookie", String.class, String.class ); + resp.put( "set_content_type", new LuanJavaFunction(HttpServletResponse.class.getMethod("setContentType",String.class),response) ); + add( resp, "text_writer" ); + return resp; + } + + private void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { + t.put( method, new LuanJavaFunction(HttpLib.class.getMethod(method,parameterTypes),this) ); + } +/* + public void text_write(LuanState luan,Object... args) throws LuanException, IOException { + if( writer == null ) + writer = response.getWriter(); + for( Object obj : args ) { + writer.print( luan.toString(obj) ); + } + } +*/ + public LuanTable text_writer() throws IOException { + return IoLib.textWriter(response.getWriter()); + } + + public String get_cookie_value(String name) { + return getCookieValue(request, name); + } + + public String current_url() { + return getCurrentURL(request); + } + + public void send_redirect(String redirectUrl) + throws IOException + { + response.sendRedirect(redirectUrl); + throw new LuanExitException(); + } + + public void send_error(int code,String text) + throws IOException + { + response.sendError(code, text); + throw new LuanExitException(); + } + + public void set_cookie(String name,String value,boolean isPersistent, String domain) { + setCookie(request,response,name,value,isPersistent,domain); + } + + public void remove_cookie(String name, String domain) { + removeCookie(request,response,name,domain); + } + + public Object get_session_attribute(String name) { + return request.getSession().getAttribute(name); + } + + public void set_session_attribute(String name,Object value) { + request.getSession().setAttribute(name,value); + } + + + // static utils + + public static String getQueryString(HttpServletRequest request) { + return getQueryString(request,0); + } + + public static String getQueryString(HttpServletRequest request,int maxValueLen) { + String method = request.getMethod(); + if( method.equals("GET") ) + return request.getQueryString(); + if( !method.equals("POST") && !method.equals("HEAD") ) + throw new RuntimeException(method); + Enumeration en = request.getParameterNames(); + StringBuilder queryBuf = new StringBuilder(); + if( !en.hasMoreElements() ) + return null; + do { + String param = (String)en.nextElement(); + String value = request.getParameter(param); + if( maxValueLen > 0 ) { + int len = value.length(); + if( len > maxValueLen ) + value = value.substring(0,maxValueLen) + "..." + (len-maxValueLen); + } + queryBuf.append(param); + queryBuf.append('='); + queryBuf.append(value); + queryBuf.append('&'); + } while( en.hasMoreElements() ); + queryBuf.deleteCharAt(queryBuf.length() - 1); + return queryBuf.toString(); + } + + public static String getCurrentURL(HttpServletRequest request) { + return getCurrentURL(request,0); + } + + public static String getCurrentURL(HttpServletRequest request,int maxValueLen) { +// StringBuffer buf = HttpUtils.getRequestURL(request); + StringBuffer buf = request.getRequestURL(); + String qStr = getQueryString(request,maxValueLen); + if(qStr != null && qStr.length() > 0) { + buf.append('?'); + buf.append(qStr); + } + return buf.toString(); + } + + private static String escape(String value) { + return value.replaceAll(";", "%3B"); + } + + private static String unescape(String value) { + return value.replaceAll("%3B", ";"); + } + + private static Cookie getCookie(HttpServletRequest request,String name) { + Cookie[] cookies = request.getCookies(); + if( cookies == null ) + return null; + for (Cookie cookie : cookies) { + if (cookie.getName().equals(name)) + return cookie; + } + return null; + } + + public static String getCookieValue(HttpServletRequest request,String name) { + Cookie cookie = getCookie(request,name); + return cookie==null ? null : unescape(cookie.getValue()); + } + + public static void setCookie(HttpServletRequest request,HttpServletResponse response,String name,String value,boolean isPersistent, String domain) { + Cookie cookie = getCookie(request,name); + if( cookie==null || !cookie.getValue().equals(value) ) { + cookie = new Cookie(name, escape(value)); + cookie.setPath("/"); + if (domain != null && domain.length() > 0) + cookie.setDomain(domain); + if( isPersistent ) + cookie.setMaxAge(10000000); + response.addCookie(cookie); + } + } + + public static void removeCookie(HttpServletRequest request, + HttpServletResponse response, + String name, + String domain + + ) { + Cookie cookie = getCookie(request, name); + if(cookie != null) { + Cookie delCookie = new Cookie(name, "delete"); + delCookie.setPath("/"); + delCookie.setMaxAge(0); + if (domain != null && domain.length() > 0) + delCookie.setDomain(domain); + response.addCookie(delCookie); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/IoLib.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,504 @@ +package luan.modules; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.Reader; +import java.io.Writer; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.URL; +import java.net.Socket; +import java.net.ServerSocket; +import java.net.MalformedURLException; +import luan.LuanState; +import luan.LuanTable; +import luan.LuanFunction; +import luan.LuanJavaFunction; +import luan.LuanException; + + +public final class IoLib { + + public static final LuanFunction LOADER = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + LuanTable module = new LuanTable(); + try { + add( module, "File", LuanState.class, String.class ); + add( module, "read_console_line", String.class ); + + LuanTable stdin = new LuanTable(); + stdin.put( "read_text", new LuanJavaFunction( + IoLib.class.getMethod( "stdin_read_text" ), null + ) ); + stdin.put( "read_binary", new LuanJavaFunction( + IoLib.class.getMethod( "stdin_read_binary" ), null + ) ); + stdin.put( "read_lines", new LuanJavaFunction( + IoLib.class.getMethod( "stdin_read_lines" ), null + ) ); + stdin.put( "read_blocks", new LuanJavaFunction( + IoLib.class.getMethod( "stdin_read_blocks", Integer.class ), null + ) ); + module.put( "stdin", stdin ); + + add( module, "Socket", String.class, Integer.TYPE ); + add( module, "socket_server", Integer.TYPE ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + module.put( "stdout", textWriter(System.out) ); + module.put( "stderr", textWriter(System.err) ); + return module; + } + }; + + private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { + t.put( method, new LuanJavaFunction(IoLib.class.getMethod(method,parameterTypes),null) ); + } + + + public static String stdin_read_text() throws IOException { + return Utils.readAll(new InputStreamReader(System.in)); + } + + public static byte[] stdin_read_binary() throws IOException { + return Utils.readAll(System.in); + } + + public static LuanFunction stdin_read_lines() throws IOException { + return lines(new BufferedReader(new InputStreamReader(System.in))); + } + + public static LuanFunction stdin_read_blocks(Integer blockSize) throws IOException { + int n = blockSize!=null ? blockSize : Utils.bufSize; + return blocks(System.in,n); + } + + public static String read_console_line(String prompt) throws IOException { + if( prompt==null ) + prompt = "> "; + return System.console().readLine(prompt); + } + + + public interface LuanWriter { + public void write(LuanState luan,Object... args) throws LuanException, IOException; + public void close() throws IOException; + } + + public static LuanTable textWriter(final PrintStream out) { + LuanWriter luanWriter = new LuanWriter() { + + public void write(LuanState luan,Object... args) throws LuanException { + for( Object obj : args ) { + out.print( luan.toString(obj) ); + } + } + + public void close() { + out.close(); + } + }; + return writer(luanWriter); + } + + public static LuanTable textWriter(final Writer out) { + LuanWriter luanWriter = new LuanWriter() { + + public void write(LuanState luan,Object... args) throws LuanException, IOException { + for( Object obj : args ) { + out.write( luan.toString(obj) ); + } + } + + public void close() throws IOException { + out.close(); + } + }; + return writer(luanWriter); + } + + private static LuanTable writer(LuanWriter luanWriter) { + LuanTable writer = new LuanTable(); + try { + writer.put( "write", new LuanJavaFunction( + LuanWriter.class.getMethod( "write", LuanState.class, new Object[0].getClass() ), luanWriter + ) ); + writer.put( "close", new LuanJavaFunction( + LuanWriter.class.getMethod( "close" ), luanWriter + ) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return writer; + } + + + public static LuanTable binaryWriter(final OutputStream out) { + LuanTable writer = new LuanTable(); + try { + writer.put( "write", new LuanJavaFunction( + OutputStream.class.getMethod( "write", new byte[0].getClass() ), out + ) ); + writer.put( "close", new LuanJavaFunction( + OutputStream.class.getMethod( "close" ), out + ) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return writer; + } + + static LuanFunction lines(final BufferedReader in) { + return new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + try { + if( args.length > 0 ) { + if( args.length > 1 || !"close".equals(args[0]) ) + throw luan.exception( "the only argument allowed is 'close'" ); + in.close(); + return null; + } + String rtn = in.readLine(); + if( rtn==null ) + in.close(); + return rtn; + } catch(IOException e) { + throw luan.exception(e); + } + } + }; + } + + static LuanFunction blocks(final InputStream in,final int blockSize) { + return new LuanFunction() { + final byte[] a = new byte[blockSize]; + + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + try { + if( args.length > 0 ) { + if( args.length > 1 || !"close".equals(args[0]) ) + throw luan.exception( "the only argument allowed is 'close'" ); + in.close(); + return null; + } + if( in.read(a) == -1 ) { + in.close(); + return null; + } + return a; + } catch(IOException e) { + throw luan.exception(e); + } + } + }; + } + + + + public static abstract class LuanIn { + abstract InputStream inputStream() throws IOException; + public abstract String to_string(); + + public String read_text() throws IOException { + Reader in = new InputStreamReader(inputStream()); + String s = Utils.readAll(in); + in.close(); + return s; + } + + public byte[] read_binary() throws IOException { + InputStream in = inputStream(); + byte[] a = Utils.readAll(in); + in.close(); + return a; + } + + public LuanFunction read_lines() throws IOException { + return lines(new BufferedReader(new InputStreamReader(inputStream()))); + } + + public LuanFunction read_blocks(Integer blockSize) throws IOException { + int n = blockSize!=null ? blockSize : Utils.bufSize; + return blocks(inputStream(),n); + } + + LuanTable table() { + LuanTable tbl = new LuanTable(); + try { + tbl.put( "to_string", new LuanJavaFunction( + LuanIn.class.getMethod( "to_string" ), this + ) ); + tbl.put( "read_text", new LuanJavaFunction( + LuanIn.class.getMethod( "read_text" ), this + ) ); + tbl.put( "read_binary", new LuanJavaFunction( + LuanIn.class.getMethod( "read_binary" ), this + ) ); + tbl.put( "read_lines", new LuanJavaFunction( + LuanIn.class.getMethod( "read_lines" ), this + ) ); + tbl.put( "read_blocks", new LuanJavaFunction( + LuanIn.class.getMethod( "read_blocks", Integer.class ), this + ) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return tbl; + } + } + + public static abstract class LuanIO extends LuanIn { + abstract OutputStream outputStream() throws IOException; + + public void write(LuanState luan,Object obj) throws LuanException, IOException { + if( obj instanceof String ) { + String s = (String)obj; + Writer out = new OutputStreamWriter(outputStream()); + out.write(s); + out.close(); + return; + } + if( obj instanceof byte[] ) { + byte[] a = (byte[])obj; + OutputStream out = outputStream(); + Utils.copyAll(new ByteArrayInputStream(a),out); + out.close(); + return; + } + throw luan.exception( "bad argument #1 to 'write' (string or binary expected)" ); + } + + public LuanTable text_writer() throws IOException { + return textWriter(new BufferedWriter(new OutputStreamWriter(outputStream()))); + } + + public LuanTable binary_writer() throws IOException { + return binaryWriter(new BufferedOutputStream(outputStream())); + } + + @Override LuanTable table() { + LuanTable tbl = super.table(); + try { + tbl.put( "write", new LuanJavaFunction( + LuanIO.class.getMethod( "write", LuanState.class, Object.class ), this + ) ); + tbl.put( "text_writer", new LuanJavaFunction( + LuanIO.class.getMethod( "text_writer" ), this + ) ); + tbl.put( "binary_writer", new LuanJavaFunction( + LuanIO.class.getMethod( "binary_writer" ), this + ) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return tbl; + } + } + + public static final class LuanUrl extends LuanIn { + private final URL url; + + public LuanUrl(String s) throws MalformedURLException { + this.url = new URL(s); + } + + @Override InputStream inputStream() throws IOException { + return url.openStream(); + } + + @Override public String to_string() { + return url.toString(); + } + } + + public static final class LuanFile extends LuanIO { + private final File file; + + public LuanFile(String name) { + this(new File(name)); + } + + public LuanFile(File file) { + this.file = file; + } + + @Override InputStream inputStream() throws IOException { + return new FileInputStream(file); + } + + @Override OutputStream outputStream() throws IOException { + return new FileOutputStream(file); + } + + @Override public String to_string() { + return file.toString(); + } + + public LuanTable child(String name) { + return new LuanFile(new File(file,name)).table(); + } + + public LuanTable children() { + File[] files = file.listFiles(); + if( files==null ) + return null; + LuanTable list = new LuanTable(); + for( File f : files ) { + list.add(new LuanFile(f).table()); + } + return list; + } + + public boolean exists() { + return Utils.exists(file); + } + + @Override LuanTable table() { + LuanTable tbl = super.table(); + try { + tbl.put( "name", new LuanJavaFunction( + File.class.getMethod( "getName" ), file + ) ); + tbl.put( "exists", new LuanJavaFunction( + LuanFile.class.getMethod( "exists" ), this + ) ); + tbl.put( "is_directory", new LuanJavaFunction( + File.class.getMethod( "isDirectory" ), file + ) ); + tbl.put( "is_file", new LuanJavaFunction( + File.class.getMethod( "isFile" ), file + ) ); + tbl.put( "delete", new LuanJavaFunction( + File.class.getMethod( "delete" ), file + ) ); + tbl.put( "mkdir", new LuanJavaFunction( + File.class.getMethod( "mkdir" ), file + ) ); + tbl.put( "mkdirs", new LuanJavaFunction( + File.class.getMethod( "mkdirs" ), file + ) ); + tbl.put( "last_modified", new LuanJavaFunction( + File.class.getMethod( "lastModified" ), file + ) ); + tbl.put( "child", new LuanJavaFunction( + LuanFile.class.getMethod( "child", String.class ), this + ) ); + tbl.put( "children", new LuanJavaFunction( + LuanFile.class.getMethod( "children" ), this + ) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return tbl; + } + } + + public static LuanIn luanIo(LuanState luan,String name) throws LuanException { + if( Utils.isFile(name) ) + return new LuanFile(name); + String url = Utils.toUrl(name); + if( url != null ) { + try { + return new LuanUrl(url); + } catch(MalformedURLException e) { + throw new RuntimeException(e); + } + } + throw luan.exception( "file '"+name+"' not found" ); + } + + public static LuanTable File(LuanState luan,String name) throws LuanException { + return luanIo(luan,name).table(); + } + + public static final class LuanSocket extends LuanIO { + private final Socket socket; + + public LuanSocket(String host,int port) throws IOException { + this(new Socket(host,port)); + } + + public LuanSocket(Socket socket) throws IOException { + this.socket = socket; + } + + @Override InputStream inputStream() throws IOException { + return socket.getInputStream(); + } + + @Override OutputStream outputStream() throws IOException { + return socket.getOutputStream(); + } + + @Override public String to_string() { + return socket.toString(); + } + + public LuanTable Pickle_client(LuanState luan) throws IOException { + DataInputStream in = new DataInputStream(new BufferedInputStream(inputStream())); + DataOutputStream out = new DataOutputStream(new BufferedOutputStream(outputStream())); + return new PickleClient(luan,in,out).table(); + } + + public void run_pickle_server(LuanState luan) throws IOException { + DataInputStream in = new DataInputStream(new BufferedInputStream(inputStream())); + DataOutputStream out = new DataOutputStream(new BufferedOutputStream(outputStream())); + new PickleServer(luan,in,out).run(); + } + + @Override LuanTable table() { + LuanTable tbl = super.table(); + try { + tbl.put( "Pickle_client", new LuanJavaFunction( + LuanSocket.class.getMethod( "Pickle_client", LuanState.class ), this + ) ); + tbl.put( "run_pickle_server", new LuanJavaFunction( + LuanSocket.class.getMethod( "run_pickle_server", LuanState.class ), this + ) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return tbl; + } + } + + public static LuanTable Socket(String host,int port) throws IOException { + return new LuanSocket(host,port).table(); + } + + public static LuanFunction socket_server(int port) throws IOException { + final ServerSocket ss = new ServerSocket(port); + return new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + try { + if( args.length > 0 ) { + if( args.length > 1 || !"close".equals(args[0]) ) + throw luan.exception( "the only argument allowed is 'close'" ); + ss.close(); + return null; + } + return new LuanSocket(ss.accept()).table(); + } catch(IOException e) { + throw luan.exception(e); + } + } + }; + } + + private void IoLib() {} // never +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/JavaLib.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,450 @@ +package luan.modules; + +import java.lang.reflect.Array; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Member; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Collections; +import java.util.Arrays; +import luan.Luan; +import luan.LuanState; +import luan.LuanTable; +import luan.MetatableGetter; +import luan.LuanException; +import luan.LuanFunction; +import luan.LuanJavaFunction; +import luan.LuanElement; + + +public final class JavaLib { + + public static final LuanFunction LOADER = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + luan.addMetatableGetter(mg); + LuanTable module = new LuanTable(); + try { + module.put( "class", new LuanJavaFunction(JavaLib.class.getMethod("getClass",LuanState.class,String.class),null) ); + add( module, "proxy", LuanState.class, Static.class, LuanTable.class, Object.class ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + luan.searchers().add(javaSearcher); + return module; + } + }; + + public static final LuanFunction javaSearcher = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + String modName = (String)args[0]; + final Static s = JavaLib.getClass(luan,modName); + if( s==null ) + return null; + LuanFunction loader = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + return s; + } + }; + return loader; + } + }; + + private static void add(LuanTable t,String method,Class<?>... parameterTypes) { + try { + t.put( method, new LuanJavaFunction(JavaLib.class.getMethod(method,parameterTypes),null) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + private static final LuanTable mt = new LuanTable(); + static { + add( mt, "__index", LuanState.class, Object.class, Object.class ); + add( mt, "__newindex", LuanState.class, Object.class, Object.class, Object.class ); + } + + private static final MetatableGetter mg = new MetatableGetter() { + public LuanTable getMetatable(Object obj) { + if( obj==null ) + return null; + return mt; + } + }; + + public static Object __index(LuanState luan,Object obj,Object key) throws LuanException { + if( obj instanceof Static ) { + if( key instanceof String ) { + String name = (String)key; + Static st = (Static)obj; + Class cls = st.cls; + if( "class".equals(name) ) { + return cls; + } else if( "new".equals(name) ) { + Constructor<?>[] constructors = cls.getConstructors(); + if( constructors.length > 0 ) { + if( constructors.length==1 ) { + return new LuanJavaFunction(constructors[0],null); + } else { + List<LuanJavaFunction> fns = new ArrayList<LuanJavaFunction>(); + for( Constructor constructor : constructors ) { + fns.add(new LuanJavaFunction(constructor,null)); + } + return new AmbiguousJavaFunction(fns); + } + } + } else if( "assert".equals(name) ) { + return new LuanJavaFunction(assertClass,new AssertClass(cls)); + } else { + List<Member> members = getStaticMembers(cls,name); + if( !members.isEmpty() ) { + return member(null,members); + } + } + } + throw luan.exception("invalid member '"+key+"' for: "+obj); + } + Class cls = obj.getClass(); + if( cls.isArray() ) { + if( "length".equals(key) ) { + return Array.getLength(obj); + } + Integer i = Luan.asInteger(key); + if( i != null ) { + return Array.get(obj,i); + } + throw luan.exception("invalid member '"+key+"' for java array: "+obj); + } + if( key instanceof String ) { + String name = (String)key; + if( "instanceof".equals(name) ) { + return new LuanJavaFunction(instanceOf,new InstanceOf(obj)); + } else { + List<Member> members = getMembers(cls,name); + if( !members.isEmpty() ) { + return member(obj,members); + } + } + } +// throw luan.exception("invalid member '"+key+"' for java object: "+obj); + return null; + } + + private static Object member(Object obj,List<Member> members) throws LuanException { + try { + if( members.size()==1 ) { + Member member = members.get(0); + if( member instanceof Static ) { + return member; + } else if( member instanceof Field ) { + Field field = (Field)member; + Object rtn = field.get(obj); + return rtn instanceof Object[] ? Arrays.asList((Object[])rtn) : rtn; + } else { + Method method = (Method)member; + return new LuanJavaFunction(method,obj); + } + } else { + List<LuanJavaFunction> fns = new ArrayList<LuanJavaFunction>(); + for( Member member : members ) { + Method method = (Method)member; + fns.add(new LuanJavaFunction(method,obj)); + } + return new AmbiguousJavaFunction(fns); + } + } catch(IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static void __newindex(LuanState luan,Object obj,Object key,Object value) throws LuanException { + if( obj instanceof Static ) { + if( key instanceof String ) { + String name = (String)key; + Static st = (Static)obj; + Class cls = st.cls; + List<Member> members = getStaticMembers(cls,name); + if( !members.isEmpty() ) { + if( members.size() != 1 ) + throw new RuntimeException("not field '"+name+"' of "+obj); + setMember(obj,members,value); + return; + } + } + throw luan.exception("invalid member '"+key+"' for: "+obj); + } + Class cls = obj.getClass(); + if( cls.isArray() ) { + Integer i = Luan.asInteger(key); + if( i != null ) { + Array.set(obj,i,value); + return; + } + throw luan.exception("invalid member '"+key+"' for java array: "+obj); + } + if( key instanceof String ) { + String name = (String)key; + List<Member> members = getMembers(cls,name); + if( !members.isEmpty() ) { + if( members.size() != 1 ) + throw new RuntimeException("not field '"+name+"' of "+obj); + setMember(obj,members,value); + return; + } + } + throw luan.exception("invalid member '"+key+"' for java object: "+obj); + } + + private static void setMember(Object obj,List<Member> members,Object value) { + Field field = (Field)members.get(0); + try { + try { + field.set(obj,value); + } catch(IllegalArgumentException e) { + Class cls = field.getType(); + if( value instanceof Number ) { + Number n = (Number)value; + if( cls.equals(Integer.TYPE) || cls.equals(Integer.class) ) { + int r = n.intValue(); + if( r==n.doubleValue() ) { + field.setInt(obj,r); + return; + } + } + } + throw e; + } + } catch(IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static boolean privateAccess = false; + private static Map<Class,Map<String,List<Member>>> memberMap = new HashMap<Class,Map<String,List<Member>>>(); + + private static synchronized List<Member> getMembers(Class cls,String name) { + Map<String,List<Member>> clsMap = memberMap.get(cls); + if( clsMap == null ) { + clsMap = new HashMap<String,List<Member>>(); + for( Class c : cls.getClasses() ) { + String s = c.getSimpleName(); + List<Member> list = new ArrayList<Member>(); + clsMap.put(s,list); + list.add(new Static(c)); + } + for( Field field : cls.getFields() ) { + String s = field.getName(); + try { + if( !cls.getField(s).equals(field) ) + continue; // not accessible + } catch(NoSuchFieldException e) { + throw new RuntimeException(e); + } + List<Member> list = new ArrayList<Member>(); + clsMap.put(s,list); + list.add(field); + } + for( Method method : cls.getMethods() ) { + String s = method.getName(); + List<Member> list = clsMap.get(s); + if( list == null || !(list.get(0) instanceof Method) ) { + list = new ArrayList<Member>(); + clsMap.put(s,list); + } + list.add(method); + } + if( privateAccess ) { + for( Method method : cls.getDeclaredMethods() ) { + String s = method.getName(); + List<Member> list = clsMap.get(s); + if( list == null ) { + list = new ArrayList<Member>(); + clsMap.put(s,list); + } else if( !(list.get(0) instanceof Method) ) + continue; + if( !list.contains(method) ) { + list.add(method); + } + } + for( Field field : cls.getDeclaredFields() ) { + String s = field.getName(); + List<Member> list = clsMap.get(s); + if( list == null ) { + list = new ArrayList<Member>(); + clsMap.put(s,list); + list.add(field); + } + } + } + for( List<Member> members : clsMap.values() ) { + for( Member m : members ) { + if( m instanceof AccessibleObject ) + ((AccessibleObject)m).setAccessible(true); + } + } + memberMap.put(cls,clsMap); + } + List<Member> rtn = clsMap.get(name); + if( rtn==null ) + rtn = Collections.emptyList(); + return rtn; + } + + private static synchronized List<Member> getStaticMembers(Class cls,String name) { + List<Member> staticMembers = new ArrayList<Member>(); + for( Member m : getMembers(cls,name) ) { + if( Modifier.isStatic(m.getModifiers()) ) + staticMembers.add(m); + } + return staticMembers; + } + + static final class Static implements Member { + final Class cls; + + Static(Class cls) { + this.cls = cls; + } + + @Override public String toString() { + return cls.toString(); + } + + @Override public Class<?> getDeclaringClass() { + return cls.getDeclaringClass(); + } + + @Override public String getName() { + return cls.getName(); + } + + @Override public int getModifiers() { + return cls.getModifiers(); + } + + @Override public boolean isSynthetic() { + return cls.isSynthetic(); + } + } + + public static Static getClass(LuanState luan,String name) throws LuanException { + Class cls; + try { + cls = Class.forName(name); + } catch(ClassNotFoundException e) { + try { + cls = Thread.currentThread().getContextClassLoader().loadClass(name); + } catch(ClassNotFoundException e2) { + return null; + } + } + return new Static(cls); + } +/* + public static void importClass(LuanState luan,String name) throws LuanException { + luan.currentEnvironment().put( name.substring(name.lastIndexOf('.')+1), getClass(luan,name) ); + } +*/ + static class AmbiguousJavaFunction extends LuanFunction { + private final Map<Integer,List<LuanJavaFunction>> fnMap = new HashMap<Integer,List<LuanJavaFunction>>(); + + AmbiguousJavaFunction(List<LuanJavaFunction> fns) { + for( LuanJavaFunction fn : fns ) { + Integer n = fn.getParameterTypes().length; + List<LuanJavaFunction> list = fnMap.get(n); + if( list==null ) { + list = new ArrayList<LuanJavaFunction>(); + fnMap.put(n,list); + } + list.add(fn); + } + } + + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + for( LuanJavaFunction fn : fnMap.get(args.length) ) { + try { + return fn.rawCall(luan,args); + } catch(IllegalArgumentException e) {} + } + throw luan.exception("no method matched args"); + } + } + + private static class InstanceOf { + private final Object obj; + + InstanceOf(Object obj) { + this.obj = obj; + } + + public boolean instanceOf(Static st) { + return st.cls.isInstance(obj); + } + } + private static final Method instanceOf; + static { + try { + instanceOf = InstanceOf.class.getMethod("instanceOf",Static.class); + instanceOf.setAccessible(true); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + + private static class AssertClass { + private final Class cls; + + AssertClass(Class cls) { + this.cls = cls; + } + + public Object assertClass(LuanState luan,Object v) throws LuanException { + if( !cls.isInstance(v) ) { + String got = v.getClass().getSimpleName(); + String expected = cls.getSimpleName(); + throw luan.exception("bad argument #1 ("+expected+" expected, got "+got+")"); + } + return v; + } + } + private static final Method assertClass; + static { + try { + assertClass = AssertClass.class.getMethod("assertClass",LuanState.class,Object.class); + assertClass.setAccessible(true); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + + public static Object proxy(final LuanState luan,Static st,final LuanTable t,final Object base) throws LuanException { + return Proxy.newProxyInstance( + st.cls.getClassLoader(), + new Class[]{st.cls}, + new InvocationHandler() { + public Object invoke(Object proxy,Method method, Object[] args) + throws Throwable + { + if( args==null ) + args = new Object[0]; + String name = method.getName(); + Object fnObj = t.get(name); + if( fnObj==null && base!=null ) + return method.invoke(base,args); + LuanFunction fn = luan.checkFunction(fnObj); + return Luan.first(luan.call(fn,name,args)); + } + } + ); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/MathLib.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,152 @@ +package luan.modules; + +import luan.LuanState; +import luan.LuanTable; +import luan.LuanFunction; +import luan.LuanJavaFunction; +import luan.LuanException; + + +public final class MathLib { + + public static final LuanFunction LOADER = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + LuanTable module = new LuanTable(); + try { + add( module, "abs", Double.TYPE ); + add( module, "acos", Double.TYPE ); + add( module, "asin", Double.TYPE ); + add( module, "atan", Double.TYPE ); + add( module, "atan2", Double.TYPE, Double.TYPE ); + add( module, "ceil", Double.TYPE ); + add( module, "cos", Double.TYPE ); + add( module, "cosh", Double.TYPE ); + add( module, "deg", Double.TYPE ); + add( module, "exp", Double.TYPE ); + add( module, "floor", Double.TYPE ); + add( module, "log", Double.TYPE ); + add( module, "min", Double.TYPE, new double[0].getClass() ); + add( module, "max", Double.TYPE, new double[0].getClass() ); + add( module, "modf", Double.TYPE ); + module.put("pi",Math.PI); + add( module, "pow", Double.TYPE, Double.TYPE ); + add( module, "rad", Double.TYPE ); + add( module, "random" ); + add( module, "sin", Double.TYPE ); + add( module, "sinh", Double.TYPE ); + add( module, "sqrt", Double.TYPE ); + add( module, "tan", Double.TYPE ); + add( module, "tanh", Double.TYPE ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return module; + } + }; + + private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { + t.put( method, new LuanJavaFunction(MathLib.class.getMethod(method,parameterTypes),null) ); + } + + public static double abs(double x) { + return Math.abs(x); + } + + public static double acos(double x) { + return Math.acos(x); + } + + public static double asin(double x) { + return Math.asin(x); + } + + public static double atan(double x) { + return Math.atan(x); + } + + public static double atan2(double y,double x) { + return Math.atan2(y,x); + } + + public static double ceil(double x) { + return Math.ceil(x); + } + + public static double cos(double x) { + return Math.cos(x); + } + + public static double cosh(double x) { + return Math.cosh(x); + } + + public static double deg(double x) { + return Math.toDegrees(x); + } + + public static double exp(double x) { + return Math.exp(x); + } + + public static double floor(double x) { + return Math.floor(x); + } + + public static double log(double x) { + return Math.log(x); + } + + public static double min(double x,double... a) { + for( double d : a ) { + if( x > d ) + x = d; + } + return x; + } + + public static double max(double x,double... a) { + for( double d : a ) { + if( x < d ) + x = d; + } + return x; + } + + public static double[] modf(double x) { + double i = (int)x; + return new double[]{i,x-i}; + } + + public static double pow(double x,double y) { + return Math.pow(x,y); + } + + public static double rad(double x) { + return Math.toRadians(x); + } + + public static double random() { + return Math.random(); + } + + public static double sin(double x) { + return Math.sin(x); + } + + public static double sinh(double x) { + return Math.sinh(x); + } + + public static double sqrt(double x) { + return Math.sqrt(x); + } + + public static double tan(double x) { + return Math.tan(x); + } + + public static double tanh(double x) { + return Math.tanh(x); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/PackageLib.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,170 @@ +package luan.modules; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import luan.Luan; +import luan.LuanState; +import luan.LuanTable; +import luan.LuanFunction; +import luan.LuanJavaFunction; +import luan.LuanElement; +import luan.LuanException; + + +public final class PackageLib { + + private static final String jpath = "luan.modules.?Lib.LOADER"; + + public static final LuanFunction LOADER = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + LuanTable module = new LuanTable(); + module.put("loaded",luan.loaded()); + module.put("preload",luan.preload()); + module.put("path","?.luan;java:luan/modules/?.luan"); + module.put("jpath",jpath); + try { + add( module, "require", LuanState.class, String.class ); + add( module, "load_lib", String.class ); + add( module, "search_path", String.class, String.class ); + add( module, "search", LuanState.class, String.class ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + LuanTable searchers = luan.searchers(); + searchers.add(preloadSearcher); + searchers.add(fileSearcher); + searchers.add(javaSearcher); + module.put("searchers",searchers); + return module; + } + }; + + private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { + t.put( method, new LuanJavaFunction(PackageLib.class.getMethod(method,parameterTypes),null) ); + } + + public static Object require(LuanState luan,String modName) throws LuanException { + LuanTable loaded = luan.loaded(); + Object mod = loaded.get(modName); + if( mod == null ) { + Object[] a = search(luan,modName); + if( a == null ) + throw luan.exception( "module '"+modName+"' not found" ); + LuanFunction loader = (LuanFunction)a[0]; + a[0] = modName; + mod = Luan.first(luan.call(loader,"<require \""+modName+"\">",a)); + if( mod != null ) { + loaded.put(modName,mod); + } else { + mod = loaded.get(modName); + if( mod==null ) + loaded.put(modName,true); + } + } + return mod; + } + + public static Object[] search(LuanState luan,String modName) throws LuanException { + List<Object> list = null; + LuanTable searchers = (LuanTable)luan.get("Package.searchers"); + if( searchers == null ) { + list = Collections.<Object>singletonList(javaSearcher); + } else { + list = searchers.asList(); + } + for( Object s : list ) { + LuanFunction searcher = (LuanFunction)s; + Object[] a = Luan.array(luan.call(searcher,"<searcher>",new Object[]{modName})); + if( a.length >= 1 && a[0] instanceof LuanFunction ) + return a; + } + return null; + } + + public static final LuanFunction preloadSearcher = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + String modName = (String)args[0]; + return luan.preload().get(modName); + } + }; + + public static String search_path(String name,String path) { + name = name.replace('.','/'); + for( String s : path.split(";") ) { + String file = s.replaceAll("\\?",name); + if( Utils.exists(file) ) + return file; + } + return null; + } + + public static final LuanFunction fileLoader = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + String fileName = (String)args[1]; + LuanFunction fn = BasicLib.load_file(luan,fileName); + return fn.call(luan,args); + } + }; + + public static final LuanFunction fileSearcher = new LuanFunction() { + @Override public Object[] call(LuanState luan,Object[] args) { + String modName = (String)args[0]; + String path = (String)luan.get("Package.path"); + if( path==null ) + return LuanFunction.NOTHING; + String file = search_path(modName,path); + return file==null ? LuanFunction.NOTHING : new Object[]{fileLoader,file}; + } + }; + + + public static final LuanFunction javaLoader = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + try { + String objName = (String)args[1]; + LuanFunction fn = load_lib(objName); + return fn.call(luan,args); + } catch(ClassNotFoundException e) { + throw new RuntimeException(e); + } catch(NoSuchFieldException e) { + throw new RuntimeException(e); + } catch(IllegalAccessException e) { + throw new RuntimeException(e); + } + } + }; + + public static final LuanFunction javaSearcher = new LuanFunction() { + @Override public Object[] call(LuanState luan,Object[] args) { + String modName = (String)args[0]; + String path = (String)luan.get("Package.jpath"); + if( path==null ) + path = jpath; + for( String s : path.split(";") ) { + String objName = s.replaceAll("\\?",modName); + try { + load_lib(objName); // throws exception if not found + return new Object[]{javaLoader,objName}; + } catch(ClassNotFoundException e) { + } catch(NoSuchFieldException e) { + } catch(IllegalAccessException e) { + } + } + return LuanFunction.NOTHING; + } + }; + + + public static LuanFunction load_lib(String path) + throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException + { + int i = path.lastIndexOf('.'); + String clsPath = path.substring(0,i); + String fld = path.substring(i+1); + Class cls = Class.forName(clsPath); + return (LuanFunction)cls.getField(fld).get(null); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/PickleClient.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,106 @@ +package luan.modules; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import luan.Luan; +import luan.LuanState; +import luan.LuanException; +import luan.LuanTable; +import luan.LuanJavaFunction; +import luan.LuanFunction; + + +public final class PickleClient { + + private final PickleCon con; + private final LuanFunction _reversed_pickle; + + PickleClient(LuanState luan,DataInputStream in,DataOutputStream out) { + this(new PickleCon(luan,in,out)); + } + + PickleClient(PickleCon con) { + this.con = con; + try { + this._reversed_pickle = new LuanJavaFunction( + PickleClient.class.getMethod( "_reversed_pickle" ), this + ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + public Object _reversed_pickle() throws LuanException, IOException { + new PickleServer(con).run(); + return con.read(); + } + + public Object call(Object... args) throws LuanException, IOException { + con.write(args); + Object[] result; + con.ioModule.put("_reversed_pickle",_reversed_pickle); + try { + result = Luan.array(con.read()); + } finally { + con.ioModule.put("_reversed_pickle",null); + } + boolean ok = (boolean)result[0]; + if( ok ) { + Object[] rtn = new Object[result.length-1]; + System.arraycopy(result,1,rtn,0,rtn.length); + return rtn; + } else { + String msg = (String)result[1]; + String src = (String)result[2]; + throw con.luan.exception( + msg + "\n" + + "in:\n" + + "------------------\n" + + formatCode(src) + "\n" + + "------------------\n" + ); + } + } + + LuanTable table() { + LuanTable tbl = new LuanTable(); + try { + tbl.put( "pickle", new LuanJavaFunction( + PickleCon.class.getMethod( "pickle", Object.class ), con + ) ); + tbl.put( "call", new LuanJavaFunction( + PickleClient.class.getMethod( "call", new Object[0].getClass() ), this + ) ); + tbl.put( "close", new LuanJavaFunction( + PickleCon.class.getMethod( "close" ), con + ) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return tbl; + } + + + public static String formatCode(String s) { + StringBuilder buf = new StringBuilder(); + int line = 1; + int i = 0; + int i2 = 0; + while( i2 != -1 ) { + buf.append( line++ ); + buf.append( '\t' ); + i2 = s.indexOf('\n',i); + String lineStr = i2 == -1 ? s.substring(i) : s.substring(i,i2+1); + int j; + for( j=0; j<lineStr.length() && lineStr.charAt(j)=='\t'; j++ ) { + buf.append( " " ); + } + buf.append( lineStr.substring(j) ); + i = i2 + 1; + } + return buf.toString(); + } + + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/PickleCon.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,134 @@ +package luan.modules; + +import java.io.OutputStream; +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Set; +import java.util.IdentityHashMap; +import java.util.Collections; +import java.util.Map; +import java.util.List; +import java.util.ArrayList; +import luan.Luan; +import luan.LuanTable; +import luan.LuanState; +import luan.LuanFunction; +import luan.LuanJavaFunction; +import luan.LuanException; + + +public final class PickleCon { + final LuanState luan; + private final DataInputStream in; + private final LuanFunction _read_binary; + final LuanTable ioModule; + private final DataOutputStream out; + private final List<byte[]> binaries = new ArrayList<byte[]>(); + String src; + private final LuanTable env = new LuanTable(); + + PickleCon(LuanState luan,DataInputStream in,DataOutputStream out) { + this.in = in; + this.luan = luan; + try { + this._read_binary = new LuanJavaFunction( + PickleCon.class.getMethod( "_read_binary", Integer.TYPE ), this + ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + this.ioModule = (LuanTable)luan.loaded().get("Io"); + + this.out = out; + } + + public byte[] _read_binary(int size) throws IOException, LuanException { + byte[] a = new byte[size]; + int i = 0; + while( i < size ) { + int n = in.read(a,i,size-i); + if( n == -1 ) + throw luan.exception( "end of stream" ); + i += n; + } + return a; + } + + public Object read() throws IOException, LuanException { + ioModule.put("_read_binary",_read_binary); + try { + src = in.readUTF(); + LuanFunction fn = BasicLib.load(luan,src,"pickle-reader",env,false); + return luan.call(fn); + } finally { + ioModule.put("_binaries",null); + ioModule.put("_read_binary",null); + } + } + + public String pickle(Object obj) throws LuanException { + if( obj == null ) + return "nil"; + if( obj instanceof Boolean ) + return Luan.toString((Boolean)obj); + if( obj instanceof Number ) + return Luan.toString((Number)obj); + if( obj instanceof String ) + return "\"" + Luan.stringEncode((String)obj) + "\""; + if( obj instanceof LuanTable ) + return pickle( (LuanTable)obj, Collections.newSetFromMap(new IdentityHashMap<LuanTable,Boolean>()) ); + if( obj instanceof byte[] ) { + byte[] a = (byte[])obj; + binaries.add(a); + return "Io._binaries[" + binaries.size() + "]"; + } + throw luan.exception( "invalid type: " + obj.getClass() ); + } + + private String pickle(Object obj,Set<LuanTable> set) throws LuanException { + return obj instanceof LuanTable ? pickle((LuanTable)obj,set) : pickle(obj); + } + + private String pickle(LuanTable tbl,Set<LuanTable> set) throws LuanException { + if( !set.add(tbl) ) { + throw luan.exception( "circular reference in table" ); + } + StringBuilder sb = new StringBuilder(); + sb.append( "{" ); + for( Map.Entry<Object,Object> entry : tbl ) { + sb.append( "[" ); + sb.append( pickle(entry.getKey(),set) ); + sb.append( "]=" ); + sb.append( pickle(entry.getValue(),set) ); + sb.append( ", " ); + } + sb.append( "}" ); + return sb.toString(); + } + + public void write(Object... args) throws LuanException, IOException { + StringBuilder sb = new StringBuilder(); + if( !binaries.isEmpty() ) { + sb.append( "Io._binaries = {}\n" ); + for( byte[] a : binaries ) { + sb.append( "Io._binaries[#Io._binaries+1] = Io._read_binary(" + a.length + ")\n" ); + } + } + for( Object obj : args ) { + sb.append( luan.toString(obj) ); + } + out.writeUTF( sb.toString() ); + for( byte[] a : binaries ) { + out.write(a); + } + out.flush(); + binaries.clear(); + } + + public void close() throws IOException { + in.close(); + out.close(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/PickleServer.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,115 @@ +package luan.modules; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.EOFException; +import java.util.List; +import java.util.ArrayList; +import luan.Luan; +import luan.LuanState; +import luan.LuanTable; +import luan.LuanFunction; +import luan.LuanJavaFunction; +import luan.LuanException; + + +public final class PickleServer { + + private final PickleCon con; + private boolean isRunning; + + PickleServer(LuanState luan,DataInputStream in,DataOutputStream out) { + this(new PickleCon(luan,in,out)); + } + + PickleServer(PickleCon con) { + this.con = con; + } + + void next() throws IOException { + try { + List<String> list = new ArrayList<String>(); + try { + Object[] result = Luan.array(con.read()); + list.add( "return true" ); + for( Object obj : result ) { + list.add( ", " ); + list.add( con.pickle(obj) ); + } + } catch(LuanException e) { +// System.out.println(e); +//e.printStackTrace(); + list.add( "return false, " ); + list.add( con.pickle(e.getMessage()) ); + list.add( ", " ); + list.add( con.pickle(con.src) ); + } + list.add( "\n" ); + con.write( list.toArray() ); + } catch(LuanException e2) { + throw new RuntimeException(e2); + } + } + + public void run() { + LuanTable ioModule = con.ioModule; + Object old_reverse_pickle = ioModule.get("reverse_pickle"); + Object old_unreverse_pickle = ioModule.get("_unreverse_pickle"); + try { + try { + ioModule.put("reverse_pickle", new LuanJavaFunction( + PickleServer.class.getMethod( "reverse_pickle", LuanFunction.class ), this + ) ); + ioModule.put("_unreverse_pickle", new LuanJavaFunction( + PickleServer.class.getMethod( "_unreverse_pickle" ), this + ) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + isRunning = true; + try { + while( isRunning ) { + next(); + } + } catch(EOFException e) { + // done + } catch(IOException e) { + e.printStackTrace(); + } + if( isRunning ) { + try { + con.close(); + } catch(IOException e) { + throw new RuntimeException(e); + } + } + } finally { + ioModule.put("reverse_pickle",old_reverse_pickle); + ioModule.put("_unreverse_pickle",old_unreverse_pickle); + } + } + + public void reverse_pickle(LuanFunction fn) throws IOException, LuanException { + try { + con.write( "return Io._reversed_pickle()\n" ); + } catch(LuanException e) { + throw new RuntimeException(e); + } + PickleClient pc = new PickleClient(con); + try { + con.luan.call(fn,new Object[]{pc.table()}); + } finally { + try { + pc.call( "Io._unreverse_pickle()\n" ); + } catch(LuanException e) { + throw new RuntimeException(e); + } + } + } + + public void _unreverse_pickle() { + isRunning = false; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/StringLib.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,264 @@ +package luan.modules; + +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import luan.Luan; +import luan.LuanState; +import luan.LuanTable; +import luan.LuanFunction; +import luan.LuanJavaFunction; +import luan.LuanElement; +import luan.LuanException; +import luan.MetatableGetter; + + +public final class StringLib { + + public static final LuanFunction LOADER = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + luan.addMetatableGetter(mg); + LuanTable module = new LuanTable(); + try { + add( module, "to_binary", String.class ); + add( module, "to_integers", String.class ); + add( module, "from_integers", new int[0].getClass() ); + add( module, "find", String.class, String.class, Integer.class, Boolean.class ); + add( module, "format", String.class, new Object[0].getClass() ); + add( module, "gmatch", String.class, String.class ); + add( module, "gsub", LuanState.class, String.class, String.class, Object.class, Integer.class ); + add( module, "len", String.class ); + add( module, "lower", String.class ); + add( module, "match", String.class, String.class, Integer.class ); + add( module, "rep", String.class, Integer.TYPE, String.class ); + add( module, "reverse", String.class ); + add( module, "sub", String.class, Integer.TYPE, Integer.class ); + add( module, "upper", String.class ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return module; + } + }; + + private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { + t.put( method, new LuanJavaFunction(StringLib.class.getMethod(method,parameterTypes),null) ); + } + + private static final LuanTable mt = new LuanTable(); + static { + try { + add( mt, "__index", LuanState.class, String.class, Object.class ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + private static final MetatableGetter mg = new MetatableGetter() { + public LuanTable getMetatable(Object obj) { + return obj instanceof String ? mt : null; + } + }; + + public static Object __index(LuanState luan,final String s,Object key) throws LuanException { + LuanTable mod = (LuanTable)luan.loaded().get("String"); + if( mod!=null ) { + Object obj = mod.get(key); + if( obj instanceof LuanFunction ) { + final LuanFunction fn = (LuanFunction)obj; + return new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + Object[] a = new Object[args.length+1]; + a[0] = s; + System.arraycopy(args,0,a,1,args.length); + return fn.call(luan,a); + } + }; + } + } + if( luan.loaded().get("Java") != null ) + return JavaLib.__index(luan,s,key); + return null; + } + + static int start(String s,int i) { + return i==0 ? 0 : i > 0 ? i - 1 : s.length() + i; + } + + static int start(String s,Integer i,int dflt) { + return i==null ? dflt : start(s,i); + } + + static int end(String s,int i) { + return i==0 ? 0 : i > 0 ? i : s.length() + i + 1; + } + + static int end(String s,Integer i,int dflt) { + return i==null ? dflt : end(s,i); + } + + public static byte[] to_binary(String s) { + return s.getBytes(); + } + + public static int[] to_integers(String s) { + char[] a = s.toCharArray(); + int[] chars = new int[a.length]; + for( int i=0; i<a.length; i++ ) { + chars[i] = a[i]; + } + return chars; + } + + public static String from_integers(int... chars) { + char[] a = new char[chars.length]; + for( int i=0; i<chars.length; i++ ) { + a[i] = (char)chars[i]; + } + return new String(a); + } + + public static int len(String s) { + return s.length(); + } + + public static String lower(String s) { + return s.toLowerCase(); + } + + public static String upper(String s) { + return s.toUpperCase(); + } + + public static String reverse(String s) { + return new StringBuilder(s).reverse().toString(); + } + + public static String rep(String s,int n,String sep) { + if( n < 1 ) + return ""; + StringBuilder buf = new StringBuilder(s); + while( --n > 0 ) { + if( sep != null ) + buf.append(sep); + buf.append(s); + } + return buf.toString(); + } + + public static String sub(String s,int i,Integer j) { + int start = start(s,i); + int end = end(s,j,s.length()); + return s.substring(start,end); + } + + public static int[] find(String s,String pattern,Integer init,Boolean plain) { + int start = start(s,init,0); + if( Boolean.TRUE.equals(plain) ) { + int i = s.indexOf(pattern,start); + return i == -1 ? null : new int[]{i+1,i+pattern.length()}; + } + Matcher m = Pattern.compile(pattern).matcher(s); + return m.find(start) ? new int[]{m.start()+1,m.end()} : null; + } + + public static String[] match(String s,String pattern,Integer init) { + int start = start(s,init,0); + Matcher m = Pattern.compile(pattern).matcher(s); + if( !m.find(start) ) + return null; + final int n = m.groupCount(); + if( n == 0 ) + return new String[]{m.group()}; + String[] rtn = new String[n]; + for( int i=0; i<n; i++ ) { + rtn[i] = m.group(i+1); + } + return rtn; + } + + public static LuanFunction gmatch(String s,String pattern) { + final Matcher m = Pattern.compile(pattern).matcher(s); + return new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + if( !m.find() ) + return null; + final int n = m.groupCount(); + if( n == 0 ) + return m.group(); + String[] rtn = new String[n]; + for( int i=0; i<n; i++ ) { + rtn[i] = m.group(i+1); + } + return rtn; + } + }; + } + + public static Object[] gsub(LuanState luan,String s,String pattern,Object repl,Integer n) throws LuanException { + int max = n==null ? Integer.MAX_VALUE : n; + final Matcher m = Pattern.compile(pattern).matcher(s); + if( repl instanceof String ) { + String replacement = (String)repl; + int i = 0; + StringBuffer sb = new StringBuffer(); + while( i<max && m.find() ) { + m.appendReplacement(sb,replacement); + i++; + } + m.appendTail(sb); + return new Object[]{ sb.toString(), i }; + } + if( repl instanceof LuanTable ) { + LuanTable t = (LuanTable)repl; + int i = 0; + StringBuffer sb = new StringBuffer(); + while( i<max && m.find() ) { + String match = m.groupCount()==0 ? m.group() : m.group(1); + Object val = t.get(match); + if( Luan.toBoolean(val) ) { + String replacement = Luan.asString(val); + if( replacement==null ) + throw luan.exception( "invalid replacement value (a "+Luan.type(val)+")" ); + m.appendReplacement(sb,replacement); + } + i++; + } + m.appendTail(sb); + return new Object[]{ sb.toString(), i }; + } + if( repl instanceof LuanFunction ) { + LuanFunction fn = (LuanFunction)repl; + int i = 0; + StringBuffer sb = new StringBuffer(); + while( i<max && m.find() ) { + Object[] args; + final int count = m.groupCount(); + if( count == 0 ) { + args = new Object[]{m.group()}; + } else { + args = new Object[count]; + for( int j=0; j<count; j++ ) { + args[j] = m.group(j); + } + } + Object val = Luan.first( luan.call(fn,"repl-arg",args) ); + if( Luan.toBoolean(val) ) { + String replacement = Luan.asString(val); + if( replacement==null ) + throw luan.exception( "invalid replacement value (a "+Luan.type(val)+")" ); + m.appendReplacement(sb,replacement); + } + i++; + } + m.appendTail(sb); + return new Object[]{ sb.toString(), i }; + } + throw luan.exception( "bad argument #3 to 'gsub' (string/function/table expected)" ); + } + + // note - String.format() is too stupid to convert between ints and floats. + public static String format(String format,Object... args) { + return String.format(format,args); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/TableLib.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,131 @@ +package luan.modules; + +import java.util.Comparator; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import luan.Luan; +import luan.LuanState; +import luan.LuanTable; +import luan.LuanFunction; +import luan.LuanJavaFunction; +import luan.LuanElement; +import luan.LuanException; +import luan.LuanRuntimeException; + + +public final class TableLib { + + public static final LuanFunction LOADER = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + LuanTable module = new LuanTable(); + try { + add( module, "concat", LuanState.class, LuanTable.class, String.class, Integer.class, Integer.class ); + add( module, "insert", LuanState.class, LuanTable.class, Integer.TYPE, Object.class ); + add( module, "pack", new Object[0].getClass() ); + add( module, "remove", LuanState.class, LuanTable.class, Integer.TYPE ); + add( module, "sort", LuanState.class, LuanTable.class, LuanFunction.class ); + add( module, "sub_list", LuanTable.class, Integer.TYPE, Integer.TYPE ); + add( module, "unpack", LuanTable.class, Integer.class, Integer.class ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return module; + } + }; + + private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { + t.put( method, new LuanJavaFunction(TableLib.class.getMethod(method,parameterTypes),null) ); + } + + public static String concat(LuanState luan,LuanTable list,String sep,Integer i,Integer j) throws LuanException { + int first = i==null ? 1 : i; + int last = j==null ? list.length() : j; + StringBuilder buf = new StringBuilder(); + for( int k=first; k<=last; k++ ) { + Object val = list.get(k); + if( val==null ) + break; + if( sep!=null && k > first ) + buf.append(sep); + String s = Luan.asString(val); + if( s==null ) + throw luan.exception( "invalid value ("+Luan.type(val)+") at index "+k+" in table for 'concat'" ); + buf.append(val); + } + return buf.toString(); + } + + public static void insert(LuanState luan,LuanTable list,int pos,Object value) throws LuanException { + try { + list.insert(pos,value); + } catch(IndexOutOfBoundsException e) { + throw luan.exception(e); + } + } + + public static Object remove(LuanState luan,LuanTable list,int pos) throws LuanException { + try { + return list.remove(pos); + } catch(IndexOutOfBoundsException e) { + throw luan.exception(e); + } + } + + private static interface LessThan { + public boolean isLessThan(Object o1,Object o2); + } + + public static void sort(final LuanState luan,LuanTable list,final LuanFunction comp) throws LuanException { + final LessThan lt; + if( comp==null ) { + lt = new LessThan() { + public boolean isLessThan(Object o1,Object o2) { + try { + return luan.isLessThan(o1,o2); + } catch(LuanException e) { + throw new LuanRuntimeException(e); + } + } + }; + } else { + lt = new LessThan() { + public boolean isLessThan(Object o1,Object o2) { + try { + return Luan.toBoolean(Luan.first(luan.call(comp,"comp-arg",new Object[]{o1,o2}))); + } catch(LuanException e) { + throw new LuanRuntimeException(e); + } + } + }; + } + try { + list.sort( new Comparator<Object>() { + public int compare(Object o1,Object o2) { + return lt.isLessThan(o1,o2) ? -1 : lt.isLessThan(o2,o1) ? 1 : 0; + } + } ); + } catch(LuanRuntimeException e) { + throw (LuanException)e.getCause(); + } + } + + public static LuanTable pack(Object... args) { + return new LuanTable(new ArrayList<Object>(Arrays.asList(args))); + } + + public static Object[] unpack(LuanTable tbl,Integer iFrom,Integer iTo) { + int from = iFrom!=null ? iFrom : 1; + int to = iTo!=null ? iTo : tbl.length(); + List<Object> list = new ArrayList<Object>(); + for( int i=from; i<=to; i++ ) { + list.add( tbl.get(i) ); + } + return list.toArray(); + } + + public static LuanTable sub_list(LuanTable list,int from,int to) { + return list.subList(from,to); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/ThreadLib.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,47 @@ +package luan.modules; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import luan.LuanState; +import luan.LuanFunction; +import luan.LuanTable; +import luan.LuanJavaFunction; +import luan.LuanException; +import luan.DeepCloner; + + +public final class ThreadLib { + + public static final LuanFunction LOADER = new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) { + LuanTable module = new LuanTable(); + try { + add( module, "fork", LuanState.class, LuanFunction.class, new Object[0].getClass() ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + return module; + } + }; + + private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { + t.put( method, new LuanJavaFunction(ThreadLib.class.getMethod(method,parameterTypes),null) ); + } + + private static final Executor exec = Executors.newCachedThreadPool(); + + public static void fork(LuanState luan,LuanFunction fn,Object... args) { + DeepCloner cloner = new DeepCloner(); + final LuanState newLuan = cloner.deepClone(luan); + final LuanFunction newFn = cloner.get(fn); + final Object[] newArgs = cloner.deepClone(args); + exec.execute(new Runnable(){public void run() { + try { + newLuan.call(newFn,"<forked>",newArgs); + } catch(LuanException e) { + e.printStackTrace(); + } + }}); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/Utils.java Sun Jun 22 04:28:32 2014 +0000 @@ -0,0 +1,85 @@ +package luan.modules; + +import java.io.Reader; +import java.io.IOException; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.File; +import java.net.URL; +import java.net.MalformedURLException; +import luan.LuanState; +import luan.LuanException; + + +public final class Utils { + private Utils() {} // never + + static final int bufSize = 8192; + + public static void checkNotNull(LuanState luan,Object v,String expected) throws LuanException { + if( v == null ) + throw luan.exception("bad argument #1 ("+expected+" expected, got nil)"); + } + + public static String readAll(Reader in) + throws IOException + { + char[] a = new char[bufSize]; + StringBuilder buf = new StringBuilder(); + int n; + while( (n=in.read(a)) != -1 ) { + buf.append(a,0,n); + } + return buf.toString(); + } + + public static void copyAll(InputStream in,OutputStream out) + throws IOException + { + byte[] a = new byte[bufSize]; + int n; + while( (n=in.read(a)) != -1 ) { + out.write(a,0,n); + } + } + + public static byte[] readAll(InputStream in) + throws IOException + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + copyAll(in,out); + return out.toByteArray(); + } + + public static boolean exists(File file) { + try { + return file.exists() && file.getName().equals(file.getCanonicalFile().getName()); + } catch(IOException e) { + throw new RuntimeException(e); + } + } + + public static boolean isFile(String path) { + return exists(new File(path)); + } + + public static String toUrl(String path) { + if( path.indexOf(':') == -1 ) + return null; + if( path.startsWith("java:") ) { + path = path.substring(5); + URL url = ClassLoader.getSystemResource(path); + return url==null ? null : url.toString(); + } + try { + new URL(path); + return path; + } catch(MalformedURLException e) {} + return null; + } + + public static boolean exists(String path) { + return isFile(path) || toUrl(path)!=null; + } +}