Mercurial Hosting > luan
changeset 43:80b67b1a653c
implement string lib
git-svn-id: https://luan-java.googlecode.com/svn/trunk@44 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Tue, 25 Dec 2012 03:42:42 +0000 |
parents | 786699c78837 |
children | 57054fa43189 |
files | src/luan/LuaException.java src/luan/LuaJavaFunction.java src/luan/lib/BasicLib.java src/luan/lib/StringLib.java src/luan/tools/CmdLine.java |
diffstat | 5 files changed, 307 insertions(+), 81 deletions(-) [+] |
line wrap: on
line diff
diff -r 786699c78837 -r 80b67b1a653c src/luan/LuaException.java --- a/src/luan/LuaException.java Sun Dec 23 06:36:56 2012 +0000 +++ b/src/luan/LuaException.java Tue Dec 25 03:42:42 2012 +0000 @@ -35,12 +35,11 @@ private static String stackTrace(LuaState lua,LuaElement el,Object msg) { StringBuilder buf = new StringBuilder(); - int i = lua.stackTrace.size() - 1; - do { + for( int i = lua.stackTrace.size() - 1; i>=0; i-- ) { StackTraceElement stackTraceElement = lua.stackTrace.get(i); buf.append( "\n\t" ).append( el.toString(stackTraceElement.fnName) ); el = stackTraceElement.call; - } while( --i >= 0 ); + } if( msg instanceof LuaException ) { LuaException le = (LuaException)msg; buf.append( "\ncaused by:" ).append( le.stackTrace );
diff -r 786699c78837 -r 80b67b1a653c src/luan/LuaJavaFunction.java --- a/src/luan/LuaJavaFunction.java Sun Dec 23 06:36:56 2012 +0000 +++ b/src/luan/LuaJavaFunction.java Tue Dec 25 03:42:42 2012 +0000 @@ -81,10 +81,11 @@ if( args.length < argConverters.length ) { rtn[rtn.length-1] = Array.newInstance(varArgCls,0); } else { - Object[] varArgs = (Object[])Array.newInstance(varArgCls,args.length-n); + int len = args.length - n; + Object varArgs = Array.newInstance(varArgCls,len); ArgConverter ac = argConverters[n]; - for( int i=0; i<varArgs.length; i++ ) { - varArgs[i] = ac.convert(args[n+i]); + for( int i=0; i<len; i++ ) { + Array.set( varArgs, i, ac.convert(args[n+i]) ); } rtn[rtn.length-1] = varArgs; } @@ -110,6 +111,8 @@ private static final RtnConverter RTN_ARRAY = new RtnConverter() { public Object[] convert(Object obj) { + if( obj == null ) + return NULL_RTN; return (Object[])obj; } }; @@ -120,31 +123,56 @@ } }; + private static final Object[] NULL_RTN = new Object[1]; + private static final RtnConverter RTN_NUMBER = new RtnConverter() { public Object[] convert(Object obj) { if( obj == null ) - return new Object[1]; + return NULL_RTN; Number n = (Number)obj; LuaNumber ln = new LuaNumber(n.doubleValue()); return new Object[]{ln}; } }; + private static final RtnConverter RTN_NUMBER_ARRAY = new RtnConverter() { + public Object[] convert(Object obj) { + if( obj == null ) + return NULL_RTN; + Object[] rtn = new Object[Array.getLength(obj)]; + for( int i=0; i<rtn.length; i++ ) { + Number n = (Number)Array.get(obj,i); + if( n != null ) + rtn[i] = new LuaNumber(n.doubleValue()); + } + return rtn; + } + }; + private static RtnConverter getRtnConverter(JavaMethod m) { Class<?> rtnType = m.getReturnType(); if( rtnType == Void.TYPE ) return RTN_EMPTY; - if( Number.class.isAssignableFrom(rtnType) + if( isNumber(rtnType) ) + return RTN_NUMBER; + if( rtnType.isArray() ) { + rtnType = rtnType.getComponentType(); + if( isNumber(rtnType) ) + return RTN_NUMBER_ARRAY; + return RTN_ARRAY; + } + return RTN_ONE; + } + + private static boolean isNumber(Class<?> rtnType) { + return Number.class.isAssignableFrom(rtnType) + || rtnType == Byte.TYPE || rtnType == Short.TYPE || rtnType == Integer.TYPE || rtnType == Long.TYPE || rtnType == Float.TYPE || rtnType == Double.TYPE - ) - return RTN_NUMBER; - if( rtnType.isArray() ) - return RTN_ARRAY; - return RTN_ONE; + ; } @@ -244,6 +272,24 @@ } }; + private static final ArgConverter ARG_BYTE = new ArgConverter() { + public Object convert(Object obj) { + if( obj instanceof LuaNumber ) { + LuaNumber ln = (LuaNumber)obj; + byte i = (byte)ln.n; + if( i == ln.n ) + return Byte.valueOf(i); + } + else if( obj instanceof String ) { + String s = (String)obj; + try { + return Byte.valueOf(s); + } catch(NumberFormatException e) {} + } + return obj; + } + }; + private static boolean takesLuaState(JavaMethod m) { Class<?>[] paramTypes = m.getParameterTypes(); return paramTypes.length > 0 && paramTypes[0].equals(LuaState.class); @@ -278,6 +324,8 @@ return ARG_INTEGER; if( cls == Short.TYPE || cls.equals(Short.class) ) return ARG_SHORT; + if( cls == Byte.TYPE || cls.equals(Byte.class) ) + return ARG_BYTE; return ARG_SAME; } @@ -292,39 +340,45 @@ static JavaMethod of(final Method m) { return new JavaMethod() { - boolean isVarArgs() { + @Override boolean isVarArgs() { return m.isVarArgs(); } - Class<?>[] getParameterTypes() { + @Override Class<?>[] getParameterTypes() { return m.getParameterTypes(); } - Object invoke(Object obj,Object... args) + @Override Object invoke(Object obj,Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { return m.invoke(obj,args); } - Class<?> getReturnType() { + @Override Class<?> getReturnType() { return m.getReturnType(); } + @Override public String toString() { + return m.toString(); + } }; } static JavaMethod of(final Constructor c) { return new JavaMethod() { - boolean isVarArgs() { + @Override boolean isVarArgs() { return c.isVarArgs(); } - Class<?>[] getParameterTypes() { + @Override Class<?>[] getParameterTypes() { return c.getParameterTypes(); } - Object invoke(Object obj,Object... args) + @Override Object invoke(Object obj,Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException { return c.newInstance(args); } - Class<?> getReturnType() { + @Override Class<?> getReturnType() { return c.getDeclaringClass(); } + @Override public String toString() { + return c.toString(); + } }; }
diff -r 786699c78837 -r 80b67b1a653c src/luan/lib/BasicLib.java --- a/src/luan/lib/BasicLib.java Sun Dec 23 06:36:56 2012 +0000 +++ b/src/luan/lib/BasicLib.java Tue Dec 25 03:42:42 2012 +0000 @@ -121,66 +121,27 @@ return lua.call(fn,LuaElement.JAVA,null); } - private static class TableIter { - private final Iterator<Map.Entry<Object,Object>> iter; - - TableIter(Iterator<Map.Entry<Object,Object>> iter) { - this.iter = iter; - } - - public Object[] next() { - if( !iter.hasNext() ) - return LuaFunction.EMPTY_RTN; - Map.Entry<Object,Object> entry = iter.next(); - return new Object[]{entry.getKey(),entry.getValue()}; - } - } - private static final Method nextTableIter; - static { - try { - nextTableIter = TableIter.class.getMethod("next"); - nextTableIter.setAccessible(true); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - static LuaFunction pairs(Iterator<Map.Entry<Object,Object>> iter) { - TableIter ti = new TableIter(iter); - return new LuaJavaFunction(nextTableIter,ti); + public static LuaFunction pairs(LuaTable t) { + final Iterator<Map.Entry<Object,Object>> iter = t.iterator(); + return new LuaFunction() { + public Object[] call(LuaState lua,Object[] args) { + if( !iter.hasNext() ) + return LuaFunction.EMPTY_RTN; + Map.Entry<Object,Object> entry = iter.next(); + return new Object[]{entry.getKey(),entry.getValue()}; + } + }; } - public static LuaFunction pairs(LuaTable t) { - return pairs(t.iterator()); - } - - private static class ArrayIter { - private final LuaTable t; - private double i = 0.0; - - ArrayIter(LuaTable t) { - this.t = t; - } - - public Object[] next() { - LuaNumber n = new LuaNumber(++i); - Object val = t.get(n); - return val==null ? LuaFunction.EMPTY_RTN : new Object[]{n,val}; - } - } - private static final Method nextArrayIter; - static { - try { - nextArrayIter = ArrayIter.class.getMethod("next"); - nextArrayIter.setAccessible(true); - } catch(NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - public static LuaFunction ipairs(LuaTable t) { - ArrayIter ai = new ArrayIter(t); - return new LuaJavaFunction(nextArrayIter,ai); + public static LuaFunction ipairs(final LuaTable t) { + return new LuaFunction() { + private double i = 0.0; + public Object[] call(LuaState lua,Object[] args) { + LuaNumber n = new LuaNumber(++i); + Object val = t.get(n); + return val==null ? LuaFunction.EMPTY_RTN : new Object[]{n,val}; + } + }; } public static LuaTable get_metatable(LuaState lua,Object obj) {
diff -r 786699c78837 -r 80b67b1a653c src/luan/lib/StringLib.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/lib/StringLib.java Tue Dec 25 03:42:42 2012 +0000 @@ -0,0 +1,210 @@ +package luan.lib; + +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import luan.Lua; +import luan.LuaState; +import luan.LuaTable; +import luan.LuaFunction; +import luan.LuaJavaFunction; +import luan.LuaNumber; +import luan.LuaElement; +import luan.LuaException; + + +public final class StringLib { + + public static void register(LuaState lua) { + LuaTable module = new LuaTable(); + LuaTable global = lua.global(); + global.put("string",module); + try { + module.put( "byte", new LuaJavaFunction(StringLib.class.getMethod("byte_",String.class,Integer.class,Integer.class),null) ); + module.put( "char", new LuaJavaFunction(StringLib.class.getMethod("char_",new byte[0].getClass()),null) ); + add( module, "find", String.class, String.class, Integer.class, Boolean.class ); + add( module, "gmatch", String.class, String.class ); + add( module, "gsub", LuaState.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); + } + } + + private static void add(LuaTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException { + t.put( method, new LuaJavaFunction(StringLib.class.getMethod(method,parameterTypes),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[] byte_(String s,Integer i,Integer j) { + int start = start(s,i,0); + int end = end(s,j,start+1); + return s.substring(start,end).getBytes(); + } + + public static String char_(byte... bytes) { + return new String(bytes); + } + + // format is hard because String.format() is too stupid to convert ints to floats. + + 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); + } + return rtn; + } + + public static LuaFunction gmatch(String s,String pattern) { + final Matcher m = Pattern.compile(pattern).matcher(s); + return new LuaFunction() { + public Object[] call(LuaState lua,Object[] args) { + if( !m.find() ) + return LuaFunction.EMPTY_RTN; + 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); + } + return rtn; + } + }; + } + + public static Object[] gsub(LuaState lua,String s,String pattern,Object repl,Integer n) throws LuaException { + 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(), new LuaNumber(i) }; + } + if( repl instanceof LuaTable ) { + LuaTable t = (LuaTable)repl; + int i = 0; + StringBuffer sb = new StringBuffer(); + while( i<max && m.find() ) { + String match = m.groupCount()==0 ? m.group() : m.group(0); + Object val = t.get(match); + if( Lua.toBoolean(val) ) { + String replacement = Lua.asString(val); + if( replacement==null ) + throw new LuaException( lua, LuaElement.JAVA, "invalid replacement value (a "+Lua.type(val)+")" ); + m.appendReplacement(sb,replacement); + } + i++; + } + m.appendTail(sb); + return new Object[]{ sb.toString(), new LuaNumber(i) }; + } + if( repl instanceof LuaFunction ) { + LuaFunction fn = (LuaFunction)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 = Lua.first( lua.call(fn,LuaElement.JAVA,"repl-arg",args) ); + if( Lua.toBoolean(val) ) { + String replacement = Lua.asString(val); + if( replacement==null ) + throw new LuaException( lua, LuaElement.JAVA, "invalid replacement value (a "+Lua.type(val)+")" ); + m.appendReplacement(sb,replacement); + } + i++; + } + m.appendTail(sb); + return new Object[]{ sb.toString(), new LuaNumber(i) }; + } + throw new LuaException( lua, LuaElement.JAVA, "bad argument #3 to 'gsub' (string/function/table expected)" ); + } + +}
diff -r 786699c78837 -r 80b67b1a653c src/luan/tools/CmdLine.java --- a/src/luan/tools/CmdLine.java Sun Dec 23 06:36:56 2012 +0000 +++ b/src/luan/tools/CmdLine.java Tue Dec 25 03:42:42 2012 +0000 @@ -4,6 +4,7 @@ import java.util.Scanner; import luan.lib.BasicLib; import luan.lib.JavaLib; +import luan.lib.StringLib; import luan.Lua; import luan.LuaState; import luan.LuaFunction; @@ -19,6 +20,7 @@ LuaState lua = LuaCompiler.newLuaState(); BasicLib.register(lua); JavaLib.register(lua); + StringLib.register(lua); BasicLib.make_standard(lua); boolean interactive = false; boolean showVersion = false; @@ -75,8 +77,8 @@ LuaFunction fn = BasicLib.load_file(lua,file); lua.call(fn,null,null,varArgs); } catch(LuaException e) { - System.err.println("error: "+e.getMessage()); -// e.printStackTrace(); +// System.err.println("error: "+e.getMessage()); + e.printStackTrace(); System.exit(-1); } }