Mercurial Hosting > luan
diff src/luan/modules/StringLuan.java @ 168:ebe9db183eb7
rename *Lib.java to *Luan.java
git-svn-id: https://luan-java.googlecode.com/svn/trunk@169 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Sun, 22 Jun 2014 04:42:07 +0000 |
parents | src/luan/modules/StringLib.java@4c0131c2b650 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/StringLuan.java Sun Jun 22 04:42:07 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 StringLuan { + + 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(StringLuan.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 JavaLuan.__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); + } + +}