Mercurial Hosting > luan
changeset 171:3dcb0f9bee82
add core component
git-svn-id: https://luan-java.googlecode.com/svn/trunk@172 21e917c8-12df-6dd8-5cb6-c86387c605b9
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/DeepCloneable.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,7 @@ +package luan; + + +public interface DeepCloneable<T extends DeepCloneable> { + public T shallowClone(); + public void deepenClone(T clone,DeepCloner cloner); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/DeepCloner.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,45 @@ +package luan; + +import java.util.Map; +import java.util.IdentityHashMap; + + +public final class DeepCloner { + private final Map<Object,Object> cloned = new IdentityHashMap<Object,Object>(); + + public <T extends DeepCloneable<T>> T deepClone(T obj) { + @SuppressWarnings("unchecked") + T rtn = (T)cloned.get(obj); + if( rtn == null ) { + rtn = obj.shallowClone(); + cloned.put(obj,rtn); + obj.deepenClone(rtn,this); + } + return rtn; + } + + public <T> T[] deepClone(T[] obj) { + if( obj.length == 0 ) + return obj; + @SuppressWarnings("unchecked") + T[] rtn = (T[])cloned.get(obj); + if( rtn == null ) { + rtn = obj.clone(); + cloned.put(obj,rtn); + for( int i=0; i<rtn.length; i++ ) { + @SuppressWarnings("unchecked") + T t = get(rtn[i]); + rtn[i] = t; + } + } + return rtn; + } + + public <T> T get(T obj) { + if( !(obj instanceof DeepCloneable) ) + return obj; + @SuppressWarnings("unchecked") + T dc = (T)deepClone((DeepCloneable)obj); + return dc; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/Luan.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,150 @@ +package luan; + +import luan.modules.BasicLuan; + + +public final class Luan { + public static final String version = "Luan 0.1"; + + public static void main(String[] args) { + LuanState luan = LuanState.newStandard(); + try { + LuanFunction standalone = (LuanFunction)BasicLuan.load_file(luan,"java:luan/cmd_line.luan"); + luan.call(standalone,args); + } catch(LuanException e) { + System.err.println(e.getMessage()); +// e.printStackTrace(); + System.exit(-1); + } + } + + public static Object first(Object obj) { + if( !(obj instanceof Object[]) ) + return obj; + Object[] a = (Object[])obj; + return a.length==0 ? null : a[0]; + } + + public static Object[] array(Object obj) { + return obj instanceof Object[] ? (Object[])obj : new Object[]{obj}; + } + + public static String type(Object obj) { + if( obj == null ) + return "nil"; + if( obj instanceof String ) + return "string"; + if( obj instanceof Boolean ) + return "boolean"; + if( obj instanceof Number ) + return "number"; + if( obj instanceof LuanTable ) + return "table"; + if( obj instanceof LuanFunction ) + return "function"; + if( obj instanceof byte[] ) + return "binary"; + return "userdata"; + } + + public static boolean toBoolean(Object obj) { + return obj != null && !Boolean.FALSE.equals(obj); + } + + public static String asString(Object obj) { + if( obj instanceof String ) + return (String)obj; + if( obj instanceof Number ) + return toString((Number)obj); + return null; + } + + public static Number toNumber(Object obj) { + return toNumber(obj,null); + } + + public static Number toNumber(Object obj,Integer base) { + if( obj instanceof Number ) + return (Number)obj; + if( obj instanceof String ) { + String s = (String)obj; + try { + if( base==null ) + return Double.valueOf(s); + else + return Long.valueOf(s,base); + } catch(NumberFormatException e) {} + } + return null; + } + + public static String toString(Number n) { + if( n instanceof Integer ) + return n.toString(); + String s = n.toString(); + int iE = s.indexOf('E'); + String ending = null; + if( iE != -1 ) { + ending = s.substring(iE); + s = s.substring(0,iE); + } + if( s.endsWith(".0") ) + s = s.substring(0,s.length()-2); + if( ending != null ) + s += ending; + return s; + } + + public static Integer asInteger(Object obj) { + if( obj instanceof Integer ) + return (Integer)obj; + if( !(obj instanceof Number) ) + return null; + Number n = (Number)obj; + int i = n.intValue(); + return i==n.doubleValue() ? Integer.valueOf(i) : null; + } + + public static String toString(Object obj) { + if( obj == null ) + return "nil"; + if( obj instanceof Number ) + return Luan.toString((Number)obj); + if( obj instanceof LuanException ) { + LuanException le = (LuanException)obj; + return le.getMessage(); + } + if( obj instanceof byte[] ) + return "binary: " + Integer.toHexString(obj.hashCode()); + return obj.toString(); + } + + public static String stringEncode(String s) { + s = s.replace("\\","\\\\"); + s = s.replace("\u0007","\\a"); + s = s.replace("\b","\\b"); + s = s.replace("\f","\\f"); + s = s.replace("\n","\\n"); + s = s.replace("\r","\\r"); + s = s.replace("\t","\\t"); + s = s.replace("\u000b","\\v"); + s = s.replace("\"","\\\""); + return s; + } + + public static String repr(Object obj) { + 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 "\"" + stringEncode((String)obj) + "\""; + if( obj instanceof LuanRepr ) + return ((LuanRepr)obj).repr(); + return null; + } + + private Luan() {} // never +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/LuanBit.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,126 @@ +package luan; + +import java.util.List; + + +public final class LuanBit { + public final LuanState luan; + public final LuanElement el; + + LuanBit(LuanState luan,LuanElement el) { + this.luan = luan; + this.el = el; + } + + public LuanException exception(Object msg) { + return new LuanException(this,msg); + } + + public String stackTrace() { + StringBuilder buf = new StringBuilder(); + LuanElement el = this.el; + for( int i = luan.stackTrace.size() - 1; i>=0; i-- ) { + StackTraceElement stackTraceElement = luan.stackTrace.get(i); + buf.append( "\n\t" ).append( el.toString(stackTraceElement.fnName) ); + el = stackTraceElement.call; + } + return buf.toString(); + } + + public void dumpStack() { + System.err.println( stackTrace() ); + } + + public Object call(LuanFunction fn,String fnName,Object[] args) throws LuanException { + List<StackTraceElement> stackTrace = luan.stackTrace; + stackTrace.add( new StackTraceElement(el,fnName) ); + try { + return fn.call(luan,args); + } finally { + stackTrace.remove(stackTrace.size()-1); + } + } + + public String checkString(Object obj) throws LuanException { + String s = Luan.asString(obj); + if( s == null ) + throw exception( "attempt to use a " + Luan.type(obj) + " as a string" ); + return s; + } + + public Number checkNumber(Object obj) throws LuanException { + Number n = Luan.toNumber(obj); + if( n == null ) + throw exception( "attempt to perform arithmetic on a " + Luan.type(obj) + " value" ); + return n; + } + + public LuanFunction checkFunction(Object obj) throws LuanException { + if( obj instanceof LuanFunction ) + return (LuanFunction)obj; + throw exception( "attempt to call a " + Luan.type(obj) + " value" ); + } + + public Boolean checkBoolean(Object obj) throws LuanException { + if( obj instanceof Boolean ) + return (Boolean)obj; + throw exception( "attempt to use a " + Luan.type(obj) + " as a boolean" ); + } + + public String toString(Object obj) throws LuanException { + LuanFunction fn = getHandlerFunction("__tostring",obj); + if( fn != null ) + return checkString( Luan.first( call(fn,"__tostring",new Object[]{obj}) ) ); + return Luan.toString(obj); + } + + public String repr(Object obj) throws LuanException { + LuanFunction fn = getHandlerFunction("__repr",obj); + if( fn != null ) + return checkString( Luan.first( call(fn,"__repr",new Object[]{obj}) ) ); + String repr = Luan.repr(obj); + if( repr==null ) + throw exception( "value '" + obj + "' doesn't support repr()" ); + return repr; + } + + public LuanFunction getHandlerFunction(String op,Object obj) throws LuanException { + Object f = luan.getHandler(op,obj); + if( f == null ) + return null; + return checkFunction(f); + } + + public LuanFunction getBinHandler(String op,Object o1,Object o2) throws LuanException { + LuanFunction f1 = getHandlerFunction(op,o1); + if( f1 != null ) + return f1; + return getHandlerFunction(op,o2); + } + + public boolean isLessThan(Object o1,Object o2) throws LuanException { + if( o1 instanceof Number && o2 instanceof Number ) { + Number n1 = (Number)o1; + Number n2 = (Number)o2; + return n1.doubleValue() < n2.doubleValue(); + } + if( o1 instanceof String && o2 instanceof String ) { + String s1 = (String)o1; + String s2 = (String)o2; + return s1.compareTo(s2) < 0; + } + LuanFunction fn = getBinHandler("__lt",o1,o2); + if( fn != null ) + return Luan.toBoolean( Luan.first(call(fn,"__lt",new Object[]{o1,o2})) ); + throw exception( "attempt to compare " + Luan.type(o1) + " with " + Luan.type(o2) ); + } + + public Object arithmetic(String op,Object o1,Object o2) throws LuanException { + LuanFunction fn = getBinHandler(op,o1,o2); + if( fn != null ) + return Luan.first(call(fn,op,new Object[]{o1,o2})); + String type = Luan.toNumber(o1)==null ? Luan.type(o1) : Luan.type(o2); + throw exception("attempt to perform arithmetic on a "+type+" value"); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/LuanElement.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,20 @@ +package luan; + + +public abstract class LuanElement { + + final String toString(String fnName) { + String s = location(); + if( fnName != null ) + s += ": in function '" + fnName + "'"; + return s; + } + + abstract String location(); + + public static final LuanElement JAVA = new LuanElement(){ + @Override String location() { + return "Java"; + } + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/LuanException.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,47 @@ +package luan; + + +public class LuanException extends Exception { + private final String stackTrace; + + LuanException(LuanBit bit,Object msg) { + super(message(msg),cause(msg)); + stackTrace = stackTrace(bit,msg); + } + + @Override public String getMessage() { + return super.getMessage() + stackTrace; + } + + private String message() { + return super.getMessage(); + } + + private static Throwable cause(Object msg) { + return msg instanceof Throwable ? (Throwable)msg : null; + } + + private static String message(Object msg) { + if( msg instanceof LuanException ) { + LuanException le = (LuanException)msg; + return le.message(); +/* + } else if( msg instanceof Throwable ) { + Throwable t = (Throwable)msg; + return t.getMessage(); +*/ + } else { + return msg.toString(); + } + } + + private static String stackTrace(LuanBit bit,Object msg) { + StringBuilder buf = new StringBuilder(); + buf.append( bit.stackTrace() ); + if( msg instanceof LuanException ) { + LuanException le = (LuanException)msg; + buf.append( "\ncaused by:" ).append( le.stackTrace ); + } + return buf.toString(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/LuanExitException.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,4 @@ +package luan; + + +public final class LuanExitException extends RuntimeException {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/LuanFunction.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,18 @@ +package luan; + + +public abstract class LuanFunction implements LuanRepr { + + public abstract Object call(LuanState luan,Object[] args) throws LuanException; + + public static final Object[] NOTHING = new Object[0]; + + @Override public String toString() { + return "function: " + Integer.toHexString(hashCode()); + } + + @Override public String repr() { + return "<function>"; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/LuanJavaFunction.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,516 @@ +package luan; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Set; +import java.util.Arrays; + + +public final class LuanJavaFunction extends LuanFunction { + private final JavaMethod method; + private final Object obj; + private final RtnConverter rtnConverter; + private final boolean takesLuaState; + private final ArgConverter[] argConverters; + private final Class<?> varArgCls; + + public LuanJavaFunction(Method method,Object obj) { + this( JavaMethod.of(method), obj ); + } + + public LuanJavaFunction(Constructor constr,Object obj) { + this( JavaMethod.of(constr), obj ); + } + + LuanJavaFunction(JavaMethod method,Object obj) { + this.method = method; + this.obj = obj; + this.rtnConverter = getRtnConverter(method); + this.takesLuaState = takesLuaState(method); + this.argConverters = getArgConverters(takesLuaState,method); + if( method.isVarArgs() ) { + Class<?>[] paramTypes = method.getParameterTypes(); + this.varArgCls = paramTypes[paramTypes.length-1].getComponentType(); + } else { + this.varArgCls = null; + } + } + + @Override public String toString() { + return "java-function: " + method; + } + + public Class<?>[] getParameterTypes() { + return method.getParameterTypes(); + } + + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + args = fixArgs(luan,args); + try { + return doCall(luan,args); + } catch(IllegalArgumentException e) { + checkArgs(luan,args); + throw e; + } + } + + public Object rawCall(LuanState luan,Object[] args) throws LuanException { + args = fixArgs(luan,args); + return doCall(luan,args); + } + + private Object doCall(LuanState luan,Object[] args) throws LuanException { + Object rtn; + try { + rtn = method.invoke(obj,args); + } catch(IllegalAccessException e) { + throw new RuntimeException("method = "+method,e); + } catch(InvocationTargetException e) { + Throwable cause = e.getCause(); + if( cause instanceof Error ) + throw (Error)cause; + if( cause instanceof LuanException ) + throw (LuanException)cause; + throw luan.exception(cause); + } catch(InstantiationException e) { + throw new RuntimeException(e); + } + return rtnConverter.convert(rtn); + } + + private static final Map<Class,Class> primitiveMap = new HashMap<Class,Class>(); + static { + primitiveMap.put(Boolean.TYPE,Boolean.class); + primitiveMap.put(Character.TYPE,Character.class); + primitiveMap.put(Byte.TYPE,Byte.class); + primitiveMap.put(Short.TYPE,Short.class); + primitiveMap.put(Integer.TYPE,Integer.class); + primitiveMap.put(Long.TYPE,Long.class); + primitiveMap.put(Float.TYPE,Float.class); + primitiveMap.put(Double.TYPE,Double.class); + primitiveMap.put(Void.TYPE,Void.class); + } + + private void checkArgs(LuanState luan,Object[] args) throws LuanException { + Class<?>[] a = getParameterTypes(); + int start = takesLuaState ? 1 : 0; + for( int i=start; i<a.length; i++ ) { + Class<?> paramType = a[i]; + Class<?> type = paramType; + if( type.isPrimitive() ) + type = primitiveMap.get(type); + Object arg = args[i]; + if( !type.isInstance(arg) ) { + String expected = paramType.getSimpleName(); + if( arg==null ) { + if( paramType.isPrimitive() ) + throw luan.exception("bad argument #"+(i+1-start)+" ("+expected+" expected, got nil)"); + } else { + String got = arg.getClass().getSimpleName(); + throw luan.exception("bad argument #"+(i+1-start)+" ("+expected+" expected, got "+got+")"); + } + } + } + } + + private Object[] fixArgs(LuanState luan,Object[] args) { + int n = argConverters.length; + Object[] rtn; + int start = 0; + if( !takesLuaState && varArgCls==null && args.length == n ) { + rtn = args; + } else { + if( takesLuaState ) + n++; + rtn = new Object[n]; + if( takesLuaState ) { + rtn[start++] = luan; + } + n = argConverters.length; + if( varArgCls != null ) { + n--; + if( args.length < argConverters.length ) { + rtn[rtn.length-1] = Array.newInstance(varArgCls,0); + } else { + int len = args.length - n; + Object varArgs = Array.newInstance(varArgCls,len); + ArgConverter ac = argConverters[n]; + for( int i=0; i<len; i++ ) { + Array.set( varArgs, i, ac.convert(args[n+i]) ); + } + rtn[rtn.length-1] = varArgs; + } + } + System.arraycopy(args,0,rtn,start,Math.min(args.length,n)); + } + for( int i=0; i<n; i++ ) { + rtn[start+i] = argConverters[i].convert(rtn[start+i]); + } + return rtn; + } + + + private interface RtnConverter { + public Object convert(Object obj); + } + + private static final RtnConverter RTN_NOTHING = new RtnConverter() { + @Override public Object[] convert(Object obj) { + return NOTHING; + } + }; + + private static final RtnConverter RTN_SAME = new RtnConverter() { + @Override public Object convert(Object obj) { + return obj; + } + }; + + private static RtnConverter getRtnConverter(JavaMethod m) { + Class<?> rtnType = m.getReturnType(); + if( rtnType == Void.TYPE ) + return RTN_NOTHING; + return RTN_SAME; + } + + private static boolean isNumber(Class<?> rtnType) { + return rtnType == Short.TYPE + || rtnType == Integer.TYPE + || rtnType == Long.TYPE + || rtnType == Float.TYPE + || rtnType == Double.TYPE + ; + } + + private interface ArgConverter { + public Object convert(Object obj); + } + + private static final ArgConverter ARG_SAME = new ArgConverter() { + public Object convert(Object obj) { + return obj; + } + }; + + private static final ArgConverter ARG_BOOLEAN = new ArgConverter() { + public Object convert(Object obj) { + return Luan.toBoolean(obj); + } + }; + + private static final ArgConverter ARG_BOOLEAN_OBJ = new ArgConverter() { + public Object convert(Object obj) { + return obj==null ? null : Luan.toBoolean(obj); + } + }; + + private static final ArgConverter ARG_DOUBLE = new ArgConverter() { + public Object convert(Object obj) { + if( obj instanceof Double ) + return obj; + if( obj instanceof Number ) { + Number n = (Number)obj; + return n.doubleValue(); + } + if( obj instanceof String ) { + String s = (String)obj; + try { + return Double.valueOf(s); + } catch(NumberFormatException e) {} + } + return obj; + } + }; + + private static final ArgConverter ARG_FLOAT = new ArgConverter() { + public Object convert(Object obj) { + if( obj instanceof Float ) + return obj; + if( obj instanceof Number ) { + Number n = (Number)obj; + return n.floatValue(); + } + if( obj instanceof String ) { + String s = (String)obj; + try { + return Float.valueOf(s); + } catch(NumberFormatException e) {} + } + return obj; + } + }; + + private static final ArgConverter ARG_LONG = new ArgConverter() { + public Object convert(Object obj) { + if( obj instanceof Long ) + return obj; + if( obj instanceof Number ) { + Number n = (Number)obj; + long r = n.longValue(); + if( r==n.doubleValue() ) + return r; + } + else if( obj instanceof String ) { + String s = (String)obj; + try { + return Long.valueOf(s); + } catch(NumberFormatException e) {} + } + return obj; + } + }; + + private static final ArgConverter ARG_INTEGER = new ArgConverter() { + public Object convert(Object obj) { + if( obj instanceof Integer ) + return obj; + if( obj instanceof Number ) { + Number n = (Number)obj; + int r = n.intValue(); + if( r==n.doubleValue() ) + return r; + } + else if( obj instanceof String ) { + String s = (String)obj; + try { + return Integer.valueOf(s); + } catch(NumberFormatException e) {} + } + return obj; + } + }; + + private static final ArgConverter ARG_SHORT = new ArgConverter() { + public Object convert(Object obj) { + if( obj instanceof Short ) + return obj; + if( obj instanceof Number ) { + Number n = (Number)obj; + short r = n.shortValue(); + if( r==n.doubleValue() ) + return r; + } + else if( obj instanceof String ) { + String s = (String)obj; + try { + return Short.valueOf(s); + } catch(NumberFormatException e) {} + } + return obj; + } + }; + + private static final ArgConverter ARG_BYTE = new ArgConverter() { + public Object convert(Object obj) { + if( obj instanceof Byte ) + return obj; + if( obj instanceof Number ) { + Number n = (Number)obj; + byte r = n.byteValue(); + if( r==n.doubleValue() ) + return r; + } + else if( obj instanceof String ) { + String s = (String)obj; + try { + return Byte.valueOf(s); + } catch(NumberFormatException e) {} + } + return obj; + } + }; + + private static final ArgConverter ARG_TABLE = new ArgConverter() { + public Object convert(Object obj) { + if( obj == null ) + return null; + if( obj instanceof List ) { + @SuppressWarnings("unchecked") + List<Object> list = (List<Object>)obj; + return new LuanTable(list); + } + if( obj instanceof Map ) { + @SuppressWarnings("unchecked") + Map<Object,Object> map = (Map<Object,Object>)obj; + return new LuanTable(map); + } + if( obj instanceof Set ) { + @SuppressWarnings("unchecked") + Set<Object> set = (Set<Object>)obj; + return new LuanTable(set); + } + Class cls = obj.getClass(); + if( cls.isArray() && !cls.getComponentType().isPrimitive() ) { + Object[] a = (Object[])obj; + return new LuanTable(Arrays.asList(a)); + } + return obj; + } + }; + + private static final ArgConverter ARG_MAP = new ArgConverter() { + public Object convert(Object obj) { + if( obj instanceof LuanTable ) { + LuanTable t = (LuanTable)obj; + return t.asMap(); + } + return obj; + } + }; + + private static final ArgConverter ARG_LIST = new ArgConverter() { + public Object convert(Object obj) { + if( obj instanceof LuanTable ) { + LuanTable t = (LuanTable)obj; + if( t.isList() ) + return t.asList(); + } + return obj; + } + }; + + private static final ArgConverter ARG_SET = new ArgConverter() { + public Object convert(Object obj) { + if( obj instanceof LuanTable ) { + LuanTable t = (LuanTable)obj; + if( t.isSet() ) + return t.asSet(); + } + return obj; + } + }; + + private static class ArgArray implements ArgConverter { + private final Object[] a; + + ArgArray(Class cls) { + a = (Object[])Array.newInstance(cls.getComponentType(),0); + } + + public Object convert(Object obj) { + if( obj instanceof LuanTable ) { + LuanTable t = (LuanTable)obj; + if( t.isList() ) { + try { + return t.asList().toArray(a); + } catch(ArrayStoreException e) {} + } + } + return obj; + } + } + + private static boolean takesLuaState(JavaMethod m) { + Class<?>[] paramTypes = m.getParameterTypes(); + return paramTypes.length > 0 && paramTypes[0].equals(LuanState.class); + } + + private static ArgConverter[] getArgConverters(boolean takesLuaState,JavaMethod m) { + final boolean isVarArgs = m.isVarArgs(); + Class<?>[] paramTypes = m.getParameterTypes(); + if( takesLuaState ) { + Class<?>[] t = new Class<?>[paramTypes.length-1]; + System.arraycopy(paramTypes,1,t,0,t.length); + paramTypes = t; + } + ArgConverter[] a = new ArgConverter[paramTypes.length]; + for( int i=0; i<a.length; i++ ) { + Class<?> paramType = paramTypes[i]; + if( isVarArgs && i == a.length-1 ) + paramType = paramType.getComponentType(); + a[i] = getArgConverter(paramType); + } + return a; + } + + private static ArgConverter getArgConverter(Class<?> cls) { + if( cls == Boolean.TYPE ) + return ARG_BOOLEAN; + if( cls.equals(Boolean.class) ) + return ARG_BOOLEAN_OBJ; + if( cls == Double.TYPE || cls.equals(Double.class) ) + return ARG_DOUBLE; + if( cls == Float.TYPE || cls.equals(Float.class) ) + return ARG_FLOAT; + if( cls == Long.TYPE || cls.equals(Long.class) ) + return ARG_LONG; + if( cls == Integer.TYPE || cls.equals(Integer.class) ) + 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; + if( cls.equals(LuanTable.class) ) + return ARG_TABLE; + if( cls.equals(Map.class) ) + return ARG_MAP; + if( cls.equals(List.class) ) + return ARG_LIST; + if( cls.equals(Set.class) ) + return ARG_SET; + if( cls.isArray() && !cls.getComponentType().isPrimitive() ) + return new ArgArray(cls); + return ARG_SAME; + } + + + + private static abstract class JavaMethod { + abstract boolean isVarArgs(); + abstract Class<?>[] getParameterTypes(); + abstract Object invoke(Object obj,Object... args) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException; + abstract Class<?> getReturnType(); + + static JavaMethod of(final Method m) { + return new JavaMethod() { + @Override boolean isVarArgs() { + return m.isVarArgs(); + } + @Override Class<?>[] getParameterTypes() { + return m.getParameterTypes(); + } + @Override Object invoke(Object obj,Object... args) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException + { + return m.invoke(obj,args); + } + @Override Class<?> getReturnType() { + return m.getReturnType(); + } + @Override public String toString() { + return m.toString(); + } + }; + } + + static JavaMethod of(final Constructor c) { + return new JavaMethod() { + @Override boolean isVarArgs() { + return c.isVarArgs(); + } + @Override Class<?>[] getParameterTypes() { + return c.getParameterTypes(); + } + @Override Object invoke(Object obj,Object... args) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException + { + return c.newInstance(args); + } + @Override Class<?> getReturnType() { + return c.getDeclaringClass(); + } + @Override public String toString() { + return c.toString(); + } + }; + } + + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/LuanRepr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,6 @@ +package luan; + + +public interface LuanRepr { + public String repr(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/LuanRuntimeException.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,8 @@ +package luan; + + +public final class LuanRuntimeException extends RuntimeException { + public LuanRuntimeException(LuanException e) { + super(e); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/LuanSource.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,62 @@ +package luan; + + +public final class LuanSource { + public final String name; + public final String text; + + public LuanSource(String name,String text) { + this.name = name; + this.text = text; + } + + public static final class CompilerElement extends LuanElement { + public final LuanSource source; + + public CompilerElement(LuanSource source) { + if( source==null ) + throw new NullPointerException("source is null"); + this.source = source; + } + + @Override String location() { + return "Compiling " + source.name; + } + } + + public static final class Element extends LuanElement { + public final LuanSource source; + public final int start; + public final int end; + + public Element(LuanSource source,int start,int end) { + if( source==null ) + throw new NullPointerException("source is null"); + this.source = source; + this.start = start; + while( end > 0 && Character.isWhitespace(source.text.charAt(end-1)) ) { + end--; + } + this.end = end; + } + + public String text() { + return source.text.substring(start,end); + } + + @Override String location() { + return source.name + ':' + lineNumber(); + } + + private int lineNumber() { + int line = 0; + int i = -1; + do { + line++; + i = source.text.indexOf('\n',i+1); + } while( i != -1 && i < start ); + return line; + } + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/LuanState.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,181 @@ +package luan; + +import java.io.InputStream; +import java.io.PrintStream; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.LinkedHashMap; +import luan.impl.LuanCompiler; +import luan.modules.BasicLuan; +import luan.modules.PackageLuan; + + +public abstract class LuanState implements DeepCloneable<LuanState> { + private final LuanBit JAVA = bit(LuanElement.JAVA); + + public LuanException exception(Object msg) { + return JAVA.exception(msg); + } + + public Object call(LuanFunction fn) throws LuanException { + return call(fn,null,LuanFunction.NOTHING); + } + + public Object call(LuanFunction fn,String fnName) throws LuanException { + return call(fn,fnName,LuanFunction.NOTHING); + } + + public Object call(LuanFunction fn,Object[] args) throws LuanException { + return call(fn,null,args); + } + + public Object call(LuanFunction fn,String fnName,Object[] args) throws LuanException { + return JAVA.call(fn,fnName,args); + } + + public LuanFunction checkFunction(Object obj) throws LuanException { + return JAVA.checkFunction(obj); + } + + public String toString(Object obj) throws LuanException { + return JAVA.toString(obj); + } + + public String repr(Object obj) throws LuanException { + return JAVA.repr(obj); + } + + public boolean isLessThan(Object o1,Object o2) throws LuanException { + return JAVA.isLessThan(o1,o2); + } + + + + private LuanTable global; + private LuanTable loaded; + private LuanTable preload; + private LuanTable searchers; + + private final List<MetatableGetter> mtGetters; + final List<StackTraceElement> stackTrace = new ArrayList<StackTraceElement>(); + + protected LuanState() { + global = new LuanTable(); + global.put("_G",global); + global.put( "_VERSION", Luan.version ); + loaded = new LuanTable(); + preload = new LuanTable(); + searchers = new LuanTable(); + mtGetters = new ArrayList<MetatableGetter>(); + } + + protected LuanState(LuanState luan) { + mtGetters = new ArrayList<MetatableGetter>(luan.mtGetters); + } + + @Override public void deepenClone(LuanState clone,DeepCloner cloner) { + clone.global = cloner.deepClone(global); + clone.loaded = cloner.deepClone(loaded); + clone.preload = cloner.deepClone(preload); + clone.searchers = cloner.deepClone(searchers); + } + + public abstract LuanTable currentEnvironment(); + + public final LuanTable global() { + return global; + } + + public final LuanTable loaded() { + return loaded; + } + + public final LuanTable preload() { + return preload; + } + + public final LuanTable searchers() { + return searchers; + } + + public final Object get(String name) { + String[] a = name.split("\\."); + LuanTable t = loaded; + for( int i=0; i<a.length-1; i++ ) { + Object obj = t.get(a[i]); + if( !(obj instanceof LuanTable) ) + return null; + t = (LuanTable)obj; + } + return t.get(a[a.length-1]); + } + + public final Object set(String name,Object value) { + String[] a = name.split("\\."); + LuanTable t = loaded; + for( int i=0; i<a.length-1; i++ ) { + Object obj = t.get(a[i]); + if( !(obj instanceof LuanTable) ) + return null; + t = (LuanTable)obj; + } + return t.put(a[a.length-1],value); + } + + public final void globalImport(String modName) throws LuanException { + Object mod = PackageLuan.require(this,modName); + global.put(modName,mod); + } + + public static LuanState newStandard() { + try { + LuanState luan = LuanCompiler.newLuanState(); + luan.globalImport("Package"); + BasicLuan.do_file(luan,"java:luan/init.luan"); + return luan; + } catch(LuanException e) { + throw new RuntimeException(e); + } + } + + public final Object eval(String cmd) { + return eval(cmd,new LuanTable()); + } + + public final Object eval(String cmd,LuanTable env) { + try { + LuanFunction fn = BasicLuan.load(this,cmd,"eval",env,true); + return call(fn); + } catch(LuanException e) { + throw new RuntimeException(e); + } + } + + public final LuanTable getMetatable(Object obj) { + if( obj instanceof LuanTable ) { + LuanTable table = (LuanTable)obj; + return table.getMetatable(); + } + for( MetatableGetter mg : mtGetters ) { + LuanTable table = mg.getMetatable(obj); + if( table != null ) + return table; + } + return null; + } + + public final void addMetatableGetter(MetatableGetter mg) { + mtGetters.add(mg); + } + + public final LuanBit bit(LuanElement el) { + return new LuanBit(this,el); + } + + public final Object getHandler(String op,Object obj) { + LuanTable t = getMetatable(obj); + return t==null ? null : t.get(op); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/LuanTable.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,388 @@ +package luan; + +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Set; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.regex.Pattern; + + +public final class LuanTable implements DeepCloneable<LuanTable>, Iterable<Map.Entry<Object,Object>>, LuanRepr { + private Map<Object,Object> map = null; + private List<Object> list = null; + private LuanTable metatable = null; + + public LuanTable() {} + + public LuanTable(LuanTable tbl) { + if( tbl.map != null ) + this.map = new HashMap<Object,Object>(tbl.map); + if( tbl.list != null ) + this.list = new ArrayList<Object>(tbl.list); + } + + public LuanTable(List<Object> list) { + this.list = list; + this.map = new HashMap<Object,Object>(); + map.put("n",list.size()); + for( int i=0; i<list.size(); i++ ) { + if( list.get(i) == null ) { + listToMap(i); + break; + } + } + } + + public LuanTable(Map<Object,Object> map) { + map.remove(null); + for( Iterator<Object> i=map.values().iterator(); i.hasNext(); ) { + if( i.next() == null ) + i.remove(); + } + this.map = map; + } + + public LuanTable(Set<Object> set) { + map = new HashMap<Object,Object>(); + for( Object obj : set ) { + if( obj != null ) + map.put(obj,Boolean.TRUE); + } + } + + @Override public LuanTable shallowClone() { + return new LuanTable(); + } + + @Override public void deepenClone(LuanTable clone,DeepCloner cloner) { + if( map != null ) { + clone.map = new HashMap<Object,Object>(); + for( Map.Entry<Object,Object> entry : map.entrySet() ) { + clone.map.put( cloner.get(entry.getKey()), cloner.get(entry.getValue()) ); + } + } + if( list != null ) { + clone.list = new ArrayList<Object>(); + for( Object obj : list ) { + clone.list.add( cloner.get(obj) ); + } + } + if( metatable != null ) + clone.metatable = cloner.deepClone(metatable); + } + + public boolean isList() { + return map==null || map.isEmpty(); + } + + public List<Object> asList() { + return list!=null ? list : Collections.emptyList(); + } + + public Map<Object,Object> asMap() { + if( list == null || list.isEmpty() ) + return map!=null ? map : Collections.emptyMap(); + Map<Object,Object> rtn = map!=null ? new HashMap<Object,Object>(map) : new HashMap<Object,Object>(); + for( ListIterator iter = list.listIterator(); iter.hasNext(); ) { + int i = iter.nextIndex(); + rtn.put(i+1,iter.next()); + } + return rtn; + } + + public boolean isSet() { + if( list != null ) { + for( Object obj : list ) { + if( obj!=null && !obj.equals(Boolean.TRUE) ) + return false; + } + } + if( map != null ) { + for( Object obj : map.values() ) { + if( !obj.equals(Boolean.TRUE) ) + return false; + } + } + return true; + } + + public Set<Object> asSet() { + if( list == null || list.isEmpty() ) + return map!=null ? map.keySet() : Collections.emptySet(); + Set<Object> rtn = map!=null ? new HashSet<Object>(map.keySet()) : new HashSet<Object>(); + for( int i=1; i<=list.size(); i++ ) { + rtn.add(i); + } + return rtn; + } + + @Override public String toString() { + return "table: " + Integer.toHexString(hashCode()); + } + + @Override public String repr() { + return repr( Collections.newSetFromMap(new IdentityHashMap<LuanTable,Boolean>()) ); + } + + private String repr(Set<LuanTable> set) { + if( !set.add(this) ) { + return "\"<circular reference>\""; + } + StringBuilder sb = new StringBuilder(); + sb.append('{'); + boolean isFirst = true; + if( list != null ) { + boolean gotNull = false; + for( int i=0; i<list.size(); i++ ) { + Object obj = list.get(i); + if( obj==null ) { + gotNull = true; + } else { + if( isFirst ) { + isFirst = false; + } else { + sb.append(", "); + } + if( gotNull ) + sb.append(i+1).append('='); + sb.append(repr(set,obj)); + } + } + } + if( map != null ) { + for( Map.Entry<Object,Object> entry : map.entrySet() ) { + if( isFirst ) { + isFirst = false; + } else { + sb.append(", "); + } + sb.append(reprKey(set,entry.getKey())).append('=').append(repr(set,entry.getValue())); + } + } + sb.append('}'); + return sb.toString(); + } + + private static final Pattern namePtn = Pattern.compile("[a-zA-Z_][a-zA-Z_0-9]*"); + + private static String reprKey(Set<LuanTable> set,Object obj) { + if( obj instanceof String ) { + String s = (String)obj; + if( namePtn.matcher(s).matches() ) + return s; + } + return "[" + repr(set,obj) + "]"; + } + + private static String repr(Set<LuanTable> set,Object obj) { + if( obj instanceof LuanTable ) { + LuanTable t = (LuanTable)obj; + return t.repr(set); + } else { + String s = Luan.repr(obj); + if( s == null ) + s = "<couldn't repr: " + Luan.stringEncode(Luan.toString(obj)) + ">"; + return s; + } + } + + public Object get(Object key) { + if( list != null ) { + Integer iT = Luan.asInteger(key); + if( iT != null ) { + int i = iT - 1; + if( i>=0 && i<list.size() ) + return list.get(i); + } + } + if( map==null ) + return null; + return map.get(key); + } + + public Object put(Object key,Object val) { + Integer iT = Luan.asInteger(key); + if( iT != null ) { + int i = iT - 1; + if( list != null || i == 0 ) { + if( i == list().size() ) { + if( val != null ) { + list.add(val); + mapToList(); + } + return null; + } else if( i>=0 && i<list.size() ) { + Object old = list.get(i); + list.set(i,val); + if( val == null ) { + listToMap(i); + } + return old; + } + } + } + if( map==null ) { + map = new HashMap<Object,Object>(); + } + if( key instanceof Number && !(key instanceof Double) ) { + Number n = (Number)key; + key = Double.valueOf(n.doubleValue()); + } + if( val == null ) { + return map.remove(key); + } else { + return map.put(key,val); + } + } + + private void mapToList() { + if( map != null ) { + while(true) { + Object v = map.remove(Double.valueOf(list.size()+1)); + if( v == null ) + break; + list.add(v); + } + } + } + + private void listToMap(int from) { + if( list != null ) { + while( list.size() > from ) { + int i = list.size() - 1; + Object v = list.remove(i); + if( v != null ) { + if( map==null ) + map = new HashMap<Object,Object>(); + map.put(i+1,v); + } + } + } + } + + private List<Object> list() { + if( list == null ) { + list = new ArrayList<Object>(); + mapToList(); + } + return list; + } + + public void insert(int pos,Object value) { + if( value==null ) + throw new UnsupportedOperationException(); + list().add(pos-1,value); + mapToList(); + } + + public void add(Object value) { + if( value==null ) + throw new UnsupportedOperationException(); + list().add(value); + mapToList(); + } + + public Object remove(int pos) { + return list().remove(pos-1); + } + + public void sort(Comparator<Object> cmp) { + Collections.sort(list(),cmp); + } + + public int length() { + return list==null ? 0 : list.size(); + } + + public Iterator<Map.Entry<Object,Object>> iterator() { + if( list == null ) { + if( map == null ) + return Collections.<Map.Entry<Object,Object>>emptyList().iterator(); + return map.entrySet().iterator(); + } + if( map == null ) + return listIterator(); + return new Iterator<Map.Entry<Object,Object>>() { + Iterator<Map.Entry<Object,Object>> iter = listIterator(); + boolean isList = true; + public boolean hasNext() { + boolean b = iter.hasNext(); + if( !b && isList ) { + iter = map.entrySet().iterator(); + isList = false; + b = iter.hasNext(); + } + return b; + } + public Map.Entry<Object,Object> next() { + return iter.next(); + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + public Iterator<Map.Entry<Object,Object>> listIterator() { + if( list == null ) + return Collections.<Map.Entry<Object,Object>>emptyList().iterator(); + final ListIterator iter = list.listIterator(); + return new Iterator<Map.Entry<Object,Object>>() { + public boolean hasNext() { + return iter.hasNext(); + } + public Map.Entry<Object,Object> next() { + Double key = Double.valueOf(iter.nextIndex()+1); + return new MapEntry(key,iter.next()); + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } +/* + public Object[] listToArray() { + return list==null ? new Object[0] : list.toArray(); + } +*/ + public LuanTable subList(int from,int to) { + return new LuanTable(new ArrayList<Object>(list().subList(from-1,to-1))); + } + + public LuanTable getMetatable() { + return metatable; + } + + public void setMetatable(LuanTable metatable) { + this.metatable = metatable; + } + + private static final class MapEntry implements Map.Entry<Object,Object> { + private final Object key; + private final Object value; + + MapEntry(Object key,Object value) { + this.key = key; + this.value = value; + } + + @Override public Object getKey() { + return key; + } + + @Override public Object getValue() { + return value; + } + + @Override public Object setValue(Object value) { + throw new UnsupportedOperationException(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/MetatableGetter.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,5 @@ +package luan; + +public interface MetatableGetter { + public LuanTable getMetatable(Object obj); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/StackTraceElement.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,12 @@ +package luan; + + +final class StackTraceElement { + final LuanElement call; + final String fnName; + + StackTraceElement(LuanElement call,String fnName) { + this.call = call; + this.fnName = fnName; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/cmd_line.luan Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,70 @@ + +local standalone_usage = [=[ +usage: java luan.CmdLine [options] [script [args]] +Available options are: + -e stat execute string 'stat' + -i enter interactive mode after executing 'script' + -v show version information + -- stop handling options + - stop handling options and execute stdin +]=] + +local function standalone_error(msg) + Io.stderr.write( msg, "\n", standalone_usage ) +end + + +local args = {...} +local interactive = false +local showVersion = false +local i = 1 +if #args == 0 then + interactive = true + showVersion = true +else + while i <= #args do + local arg = args[i] + if arg.sub(1,1) ~= "-" or arg == "--" then + break + end + if arg == "-i" then + interactive = true + elseif arg == "-v" then + showVersion = true + elseif arg == "-e" then + i = i + 1 + if i == #args then + standalone_error "'-e' needs argument" + return + end + local cmd = args[i] + local stat = load(cmd,"(command line)",true,true) + local result = Table.pack( stat() ) + if result.n > 0 then + print( Table.unpack(result,1,result.n) ) + end + elseif arg == "-" then + local src = Io.stdin.read_text() + local stdin = load(src,"stdin") + stdin() + return + else + standalone_error( "unrecognized option '"..arg.."'" ) + return + end + i = i + 1 + end +end +if showVersion then print(_VERSION) end +if i <= #args then + local file = args[i] + _G.arg = {} + for j,v in ipairs(args) do + _G.arg[j-i] = v + end + local main_file = load_file(file) + main_file( Table.unpack(_G.arg) ) +end +if interactive then + Debug.debug("> ") +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/AddExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,23 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class AddExpr extends BinaryOpExpr { + + AddExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object o1 = op1.eval(luan); + Object o2 = op2.eval(luan); + Number n1 = Luan.toNumber(o1); + Number n2 = Luan.toNumber(o2); + if( n1 != null && n2 != null ) + return n1.doubleValue() + n2.doubleValue(); + return arithmetic(luan,"__add",o1,o2); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/AndExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,18 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class AndExpr extends BinaryOpExpr { + + AndExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object v1 = op1.eval(luan); + return !Luan.toBoolean(v1) ? v1 : op2.eval(luan); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/BinaryOpExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,24 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanTable; +import luan.LuanFunction; +import luan.LuanException; +import luan.LuanSource; + + +abstract class BinaryOpExpr extends CodeImpl implements Expr { + final Expr op1; + final Expr op2; + + BinaryOpExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se); + this.op1 = op1; + this.op2 = op2; + } + + Object arithmetic(LuanStateImpl luan,String op,Object o1,Object o2) throws LuanException { + return luan.bit(se()).arithmetic("__mod",o1,o2); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/Block.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,29 @@ +package luan.impl; + +import luan.LuanException; + + +final class Block implements Stmt { + final Stmt[] stmts; + private final int stackStart; + private final int stackEnd; + + Block(Stmt[] stmts,int stackStart,int stackEnd) { + if( stmts.length==0 ) + throw new RuntimeException("empty block"); + this.stmts = stmts; + this.stackStart = stackStart; + this.stackEnd = stackEnd; + } + + @Override public void eval(LuanStateImpl luan) throws LuanException { + try { + for( Stmt stmt : stmts ) { + stmt.eval(luan); + } + } finally { + luan.stackClear(stackStart,stackEnd); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/BreakException.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,4 @@ +package luan.impl; + + +final class BreakException extends RuntimeException {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/BreakStmt.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,9 @@ +package luan.impl; + + +final class BreakStmt implements Stmt { + + @Override public void eval(LuanStateImpl luan) { + throw new BreakException(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/Closure.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,79 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanFunction; +import luan.LuanState; +import luan.LuanElement; +import luan.LuanException; +import luan.DeepCloner; +import luan.DeepCloneable; + + +final class Closure extends LuanFunction implements DeepCloneable<Closure> { + private final FnDef fnDef; + private UpValue[] upValues; + + Closure(LuanStateImpl luan,FnDef fnDef) throws LuanException { + this.fnDef = fnDef; + UpValue.Getter[] upValueGetters = fnDef.upValueGetters; + upValues = new UpValue[upValueGetters.length]; + for( int i=0; i<upValues.length; i++ ) { + upValues[i] = upValueGetters[i].get(luan); + } + } + + private Closure(Closure c) { + this.fnDef = c.fnDef; + } + + @Override public Closure shallowClone() { + return new Closure(this); + } + + @Override public void deepenClone(Closure clone,DeepCloner cloner) { + clone.upValues = cloner.deepClone(upValues); + } + + UpValue[] upValues() { + return upValues; + } + + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + return call(this,(LuanStateImpl)luan,args); + } + + private static Object call(Closure closure,LuanStateImpl luan,Object[] args) throws LuanException { + while(true) { + FnDef fnDef = closure.fnDef; + Object[] varArgs = null; + if( fnDef.isVarArg ) { + if( args.length > fnDef.numArgs ) { + varArgs = new Object[ args.length - fnDef.numArgs ]; + for( int i=0; i<varArgs.length; i++ ) { + varArgs[i] = args[fnDef.numArgs+i]; + } + } else { + varArgs = LuanFunction.NOTHING; + } + } + Object[] stack = luan.newFrame(closure,fnDef.stackSize,varArgs); + final int n = Math.min(args.length,fnDef.numArgs); + for( int i=0; i<n; i++ ) { + stack[i] = args[i]; + } + Object returnValues; + try { + fnDef.block.eval(luan); + } catch(ReturnException e) { + } finally { + returnValues = luan.returnValues; + closure = luan.tailFn; + luan.popFrame(); + } + if( closure == null ) + return returnValues; + args = Luan.array(returnValues); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/Code.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,8 @@ +package luan.impl; + +import luan.LuanSource; + + +interface Code { + public LuanSource.Element se(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/CodeImpl.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,16 @@ +package luan.impl; + +import luan.LuanSource; + + +class CodeImpl implements Code { + final LuanSource.Element se; + + CodeImpl(LuanSource.Element se) { + this.se = se; + } + + @Override public final LuanSource.Element se() { + return se; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/ConcatExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,31 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanFunction; +import luan.LuanException; +import luan.LuanSource; + + +final class ConcatExpr extends BinaryOpExpr { + + ConcatExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object o1 = op1.eval(luan); + Object o2 = op2.eval(luan); + String s1 = luan.bit(op1.se()).toString(o1); + String s2 = luan.bit(op2.se()).toString(o2); +/* + if( s1 != null && s2 != null ) + return s1 + s2; + LuanFunction fn = luan.getBinHandler(se,"__concat",o1,o2); + if( fn != null ) + return Luan.first(luan.call(fn,se,"__concat",o1,o2)); + String type = s1==null ? Luan.type(o1) : Luan.type(o2); + throw new LuanException( luan, se, "attempt to concatenate a " + type + " value" ); +*/ + return s1 + s2; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/ConstExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,25 @@ +package luan.impl; + +import luan.LuanSource; + + +final class ConstExpr extends CodeImpl implements Expr { + private final Object obj; + + ConstExpr(Object obj) { + this(null,obj); + } + + ConstExpr(LuanSource.Element se,Object obj) { + super(se); + this.obj = obj; + } + + @Override public Object eval(LuanStateImpl luan) { + return obj; + } + + @Override public String toString() { + return "(ConstExpr "+obj+")"; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/DivExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,23 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class DivExpr extends BinaryOpExpr { + + DivExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object o1 = op1.eval(luan); + Object o2 = op2.eval(luan); + Number n1 = Luan.toNumber(o1); + Number n2 = Luan.toNumber(o2); + if( n1 != null && n2 != null ) + return n1.doubleValue() / n2.doubleValue(); + return arithmetic(luan,"__div",o1,o2); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/EqExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,40 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanFunction; +import luan.LuanTable; +import luan.LuanException; +import luan.LuanSource; +import luan.LuanBit; + + +final class EqExpr extends BinaryOpExpr { + + EqExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object o1 = op1.eval(luan); + Object o2 = op2.eval(luan); + if( o1 == o2 || o1 != null && o1.equals(o2) ) + return true; + if( o1 instanceof Number && o2 instanceof Number ) { + Number n1 = (Number)o1; + Number n2 = (Number)o2; + return n1.doubleValue() == n2.doubleValue(); + } + if( o1==null || o2==null || !o1.getClass().equals(o2.getClass()) ) + return false; + LuanTable mt1 = luan.getMetatable(o1); + LuanTable mt2 = luan.getMetatable(o2); + if( mt1==null || mt2==null ) + return false; + Object f = mt1.get("__eq"); + if( f == null || !f.equals(mt2.get("__eq")) ) + return null; + LuanBit bit = luan.bit(se); + LuanFunction fn = bit.checkFunction(f); + return Luan.toBoolean( Luan.first(bit.call(fn,"__eq",new Object[]{o1,o2})) ); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/ExpList.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,96 @@ +package luan.impl; + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import luan.LuanException; +import luan.LuanSource; +import luan.LuanFunction; +import luan.Luan; + + +final class ExpList { + + static final Expressions emptyExpList = new Expressions() { + + @Override public Object[] eval(LuanStateImpl luan) { + return LuanFunction.NOTHING; + } + + @Override public LuanSource.Element se() { + return null; + } + }; + + static Expr[] toArray(List<Expressions> list) { + Expr[] a = new Expr[list.size()]; + for( int i=0; i<a.length; i++ ) { + Expressions exprs = list.get(i); + if( exprs instanceof Expr ) { + a[i] = (Expr)exprs; + } else { + a[i] = new ExpressionsExpr(exprs); + } + } + return a; + } + + static Expressions build(List<Expressions> list) { + switch(list.size()) { + case 0: + return emptyExpList; + case 1: + return list.get(0); + default: + if( list.get(list.size()-1) instanceof Expr ) { + return new ExprList1( toArray(list) ); + } else { + Expressions last = list.remove(list.size()-1); + return new ExprList2( toArray(list), last ); + } + } + } + + private static class ExprList1 implements Expressions { + private final Expr[] exprs; + + private ExprList1(Expr[] exprs) { + this.exprs = exprs; + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object[] a = new Object[exprs.length]; + for( int i=0; i<exprs.length; i++ ) { + a[i] = exprs[i].eval(luan); + } + return a; + } + + @Override public LuanSource.Element se() { + return new LuanSource.Element(exprs[0].se().source,exprs[0].se().start,exprs[exprs.length-1].se().end); + } + } + + private static class ExprList2 implements Expressions { + private final Expr[] exprs; + private final Expressions last; + + private ExprList2(Expr[] exprs,Expressions last) { + this.exprs = exprs; + this.last = last; + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + List<Object> list = new ArrayList<Object>(); + for( Expr expr : exprs ) { + list.add( expr.eval(luan) ); + } + list.addAll( Arrays.asList(Luan.array( last.eval(luan) )) ); + return list.toArray(); + } + + @Override public LuanSource.Element se() { + return new LuanSource.Element(exprs[0].se().source,exprs[0].se().start,last.se().end); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/Expr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,6 @@ +package luan.impl; + +import luan.LuanException; + + +interface Expr extends Expressions {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/Expressions.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,8 @@ +package luan.impl; + +import luan.LuanException; + + +interface Expressions extends Code { + public Object eval(LuanStateImpl luan) throws LuanException; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/ExpressionsExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,24 @@ +package luan.impl; + +import java.util.List; +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class ExpressionsExpr implements Expr { + private final Expressions expressions; + + ExpressionsExpr(Expressions expressions) { + this.expressions = expressions; + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + return Luan.first( expressions.eval(luan) ); + } + + public LuanSource.Element se() { + return expressions.se(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/ExpressionsStmt.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,17 @@ +package luan.impl; + +import luan.LuanException; + + +final class ExpressionsStmt implements Stmt { + private final Expressions expressions; + + ExpressionsStmt(Expressions expressions) { + this.expressions = expressions; + } + + @Override public void eval(LuanStateImpl luan) throws LuanException { + expressions.eval(luan); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/FnCall.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,39 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanFunction; +import luan.LuanException; +import luan.LuanSource; + + +final class FnCall extends CodeImpl implements Expressions { + final Expr fnExpr; + final Expressions args; + final String fnName; + + FnCall(LuanSource.Element se,Expr fnExpr,Expressions args) { + super(se); + this.fnExpr = fnExpr; + this.args = args; + this.fnName = fnExpr.se().text(); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + return call( luan, fnExpr.eval(luan) ); + } + + private Object call(LuanStateImpl luan,Object o) throws LuanException { + if( o instanceof LuanFunction ) { + LuanFunction fn = (LuanFunction)o; + return luan.bit(se).call( fn, fnName, Luan.array(args.eval(luan)) ); + } + Object h = luan.getHandler("__call",o); + if( h != null ) + return call(luan,h); + throw luan.bit(fnExpr.se()).exception( "attempt to call '"+fnExpr.se().text()+"' (a " + Luan.type(o) + " value)" ); + } + + @Override public String toString() { + return "(FnCall "+fnName+" "+fnExpr+" "+args+")"; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/FnDef.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,42 @@ +package luan.impl; + +import luan.LuanException; +import luan.LuanSource; + + +final class FnDef extends CodeImpl implements Expr { + final Stmt block; + final int stackSize; + final int numArgs; + final boolean isVarArg; + final UpValue.Getter[] upValueGetters; + + FnDef(LuanSource.Element se,Stmt block,int stackSize,int numArgs,boolean isVarArg,UpValue.Getter[] upValueGetters) { + super(se); + this.block = block; + this.stackSize = stackSize; + this.numArgs = numArgs; + this.isVarArg = isVarArg; + this.upValueGetters = upValueGetters; + fixReturns(block); + } + + private static void fixReturns(Stmt stmt) { + if( stmt instanceof ReturnStmt ) { + ReturnStmt rs = (ReturnStmt)stmt; + rs.throwReturnException = false; + } else if( stmt instanceof Block ) { + Block b = (Block)stmt; + fixReturns( b.stmts[b.stmts.length-1] ); + } else if( stmt instanceof IfStmt ) { + IfStmt is = (IfStmt)stmt; + fixReturns( is.thenStmt ); + fixReturns( is.elseStmt ); + } + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + return new Closure(luan,this); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/ForStmt.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,54 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanFunction; +import luan.LuanSource; +import luan.LuanBit; + + +final class ForStmt extends CodeImpl implements Stmt { + private final int iVars; + private final int nVars; + private final Expr iterExpr; + private final Stmt block; + + ForStmt(LuanSource.Element se,int iVars,int nVars,Expr iterExpr,Stmt block) { + super(se); + this.iVars = iVars; + this.nVars = nVars; + this.iterExpr = iterExpr; + this.block = block; + } + + @Override public void eval(LuanStateImpl luan) throws LuanException { + LuanFunction iter = luan.bit(se).checkFunction( iterExpr.eval(luan) ); + LuanBit bit = luan.bit(iterExpr.se()); + String name = iterExpr.se().text(); + try { + while(true) { + Object vals = bit.call(iter,name,LuanFunction.NOTHING); + if( vals==null ) + break; + if( vals instanceof Object[] ) { + Object[] a = (Object[])vals; + if( a.length==0 ) + break; + for( int i=0; i<nVars; i++ ) { + luan.stackSet( iVars+i, i < a.length ? a[i] : null ); + } + } else { + luan.stackSet( iVars, vals ); + for( int i=1; i<nVars; i++ ) { + luan.stackSet( iVars+i, null ); + } + } + block.eval(luan); + } + } catch(BreakException e) { + } finally { + luan.stackClear(iVars,iVars+nVars); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/GetLocalVar.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,17 @@ +package luan.impl; + +import luan.LuanSource; + + +final class GetLocalVar extends CodeImpl implements Expr { + private final int index; + + GetLocalVar(LuanSource.Element se,int index) { + super(se); + this.index = index; + } + + @Override public Object eval(LuanStateImpl luan) { + return luan.stackGet(index); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/GetUpVar.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,17 @@ +package luan.impl; + +import luan.LuanSource; + + +final class GetUpVar extends CodeImpl implements Expr { + private final int index; + + GetUpVar(LuanSource.Element se,int index) { + super(se); + this.index = index; + } + + @Override public Object eval(LuanStateImpl luan) { + return luan.closure().upValues()[index].get(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/IfStmt.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,27 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class IfStmt extends CodeImpl implements Stmt { + private final Expr cnd; + final Stmt thenStmt; + final Stmt elseStmt; + + IfStmt(LuanSource.Element se,Expr cnd,Stmt thenStmt,Stmt elseStmt) { + super(se); + this.cnd = cnd; + this.thenStmt = thenStmt; + this.elseStmt = elseStmt; + } + + @Override public void eval(LuanStateImpl luan) throws LuanException { + if( luan.bit(se).checkBoolean( cnd.eval(luan) ) ) { + thenStmt.eval(luan); + } else { + elseStmt.eval(luan); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/IndexExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,41 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanTable; +import luan.LuanFunction; +import luan.LuanSource; + + +final class IndexExpr extends BinaryOpExpr { + + IndexExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + return index(luan,op1.eval(luan),op2.eval(luan)); + } + + private Object index(LuanStateImpl luan,Object t,Object key) throws LuanException { + Object h; + if( t instanceof LuanTable ) { + LuanTable tbl = (LuanTable)t; + Object value = tbl.get(key); + if( value != null ) + return value; + h = luan.getHandler("__index",t); + if( h==null ) + return null; + } else { + h = luan.getHandler("__index",t); + if( h==null ) + throw luan.bit(op1.se()).exception( "attempt to index '"+op1.se().text()+"' (a " + Luan.type(t) + " value)" ); + } + if( h instanceof LuanFunction ) { + LuanFunction fn = (LuanFunction)h; + return Luan.first(luan.bit(se).call(fn,"__index",new Object[]{t,key})); + } + return index(luan,h,key); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/LeExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,38 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanFunction; +import luan.LuanException; +import luan.LuanSource; +import luan.LuanBit; + + +final class LeExpr extends BinaryOpExpr { + + LeExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object o1 = op1.eval(luan); + Object o2 = op2.eval(luan); + if( o1 instanceof Number && o2 instanceof Number ) { + Number n1 = (Number)o1; + Number n2 = (Number)o2; + return n1.doubleValue() <= n2.doubleValue(); + } + if( o1 instanceof String && o2 instanceof String ) { + String s1 = (String)o1; + String s2 = (String)o2; + return s1.compareTo(s2) <= 0; + } + LuanBit bit = luan.bit(se); + LuanFunction fn = bit.getBinHandler("__le",o1,o2); + if( fn != null ) + return Luan.toBoolean( Luan.first(bit.call(fn,"__le",new Object[]{o1,o2})) ); + fn = bit.getBinHandler("__lt",o1,o2); + if( fn != null ) + return !Luan.toBoolean( Luan.first(bit.call(fn,"__lt",new Object[]{o2,o1})) ); + throw bit.exception( "attempt to compare " + Luan.type(o1) + " with " + Luan.type(o2) ); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/LenExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,37 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanTable; +import luan.LuanFunction; +import luan.LuanException; +import luan.LuanSource; +import luan.LuanBit; + + +final class LenExpr extends UnaryOpExpr { + + LenExpr(LuanSource.Element se,Expr op) { + super(se,op); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object o = op.eval(luan); + if( o instanceof String ) { + String s = (String)o; + return s.length(); + } + if( o instanceof byte[] ) { + byte[] a = (byte[])o; + return a.length; + } + LuanBit bit = luan.bit(se); + LuanFunction fn = bit.getHandlerFunction("__len",o); + if( fn != null ) + return Luan.first(bit.call(fn,"__len",new Object[]{o})); + if( o instanceof LuanTable ) { + LuanTable t = (LuanTable)o; + return t.length(); + } + throw bit.exception( "attempt to get length of a " + Luan.type(o) + " value" ); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/LtExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,20 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanFunction; +import luan.LuanException; +import luan.LuanSource; + + +final class LtExpr extends BinaryOpExpr { + + LtExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object o1 = op1.eval(luan); + Object o2 = op2.eval(luan); + return luan.bit(se).isLessThan(o1,o2); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/LuanCompiler.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,55 @@ +package luan.impl; + +import luan.LuanFunction; +import luan.LuanState; +import luan.LuanException; +import luan.LuanSource; +import luan.LuanElement; +import luan.LuanTable; +import java.util.Map; + + +public final class LuanCompiler { + private LuanCompiler() {} // never + + public static LuanFunction compile(LuanState luan,LuanSource src,LuanTable env,boolean allowExpr) throws LuanException { + UpValue.Getter envGetter = env!=null ? new UpValue.ValueGetter(env) : new UpValue.EnvGetter(); + LuanParser parser = new LuanParser(src,envGetter); + for( Map.Entry<Object,Object> entry : luan.global() ) { + Object key = entry.getKey(); + if( key instanceof String ) + parser.addVar( (String)key, entry.getValue() ); + } + FnDef fnDef = parse(luan,parser,allowExpr); + if( env != null ) + return new Closure((LuanStateImpl)luan,fnDef); + final Closure c = new Closure((LuanStateImpl)luan,fnDef); + return new LuanFunction() { + @Override public Object call(LuanState luan,Object[] args) throws LuanException { + Object rtn = c.call(luan,args); + if( rtn instanceof Object[] && ((Object[])rtn).length==0 ) + rtn = c.upValues()[0].get(); + return rtn; + } + }; + } + + private static FnDef parse(LuanState luan,LuanParser parser,boolean allowExpr) throws LuanException { + try { + if( allowExpr ) { + FnDef fnDef = parser.Expression(); + if( fnDef != null ) + return fnDef; + } + return parser.RequiredModule(); + } catch(ParseException e) { +//e.printStackTrace(); + LuanElement le = new LuanSource.CompilerElement(parser.source); + throw luan.bit(le).exception( e.getFancyMessage() ); + } + } + + public static LuanState newLuanState() { + return new LuanStateImpl(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/LuanParser.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,1360 @@ +package luan.impl; + +import java.util.Set; +import java.util.HashSet; +import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; +import java.util.Scanner; +import luan.Luan; +import luan.LuanState; +import luan.LuanSource; + + +final class LuanParser { + + private static final class Frame { + final Frame parent; + final List<String> symbols = new ArrayList<String>(); + int stackSize = 0; + int loops = 0; + boolean isVarArg = false; + final List<String> upValueSymbols = new ArrayList<String>(); + final List<UpValue.Getter> upValueGetters = new ArrayList<UpValue.Getter>(); + + Frame(UpValue.Getter envGetter) { + this.parent = null; + upValueSymbols.add(_ENV); + upValueGetters.add(envGetter); + } + + Frame(Frame parent) { + this.parent = parent; + if( upValueIndex(_ENV) != 0 ) + throw new RuntimeException(); + } + + int stackIndex(String name) { + int i = symbols.size(); + while( --i >= 0 ) { + if( symbols.get(i).equals(name) ) + return i; + } + return -1; + } + + int upValueIndex(String name) { + int i = upValueSymbols.size(); + while( --i >= 0 ) { + if( upValueSymbols.get(i).equals(name) ) + return i; + } + if( parent==null ) + return -1; + i = parent.stackIndex(name); + if( i != -1 ) { + upValueGetters.add(new UpValue.StackGetter(i)); + } else { + i = parent.upValueIndex(name); + if( i == -1 ) + return -1; + upValueGetters.add(new UpValue.NestedGetter(i)); + } + upValueSymbols.add(name); + return upValueSymbols.size() - 1; + } + + void addUpValueGetter(String name,UpValue.Getter upValueGetter) { + upValueSymbols.add(name); + upValueGetters.add(upValueGetter); + } + } + + private static class In { + static final In NOTHING = new In(false,false); + + final boolean parens; + final boolean template; + + private In(boolean parens,boolean template) { + this.parens = parens; + this.template = template; + } + + In parens() { + return parens ? this : new In(true,template); + } + + In template() { + return template ? this : new In(parens,true); + } + } + + private static final String _ENV = "_ENV"; + private static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0]; + + final LuanSource source; + private Frame frame; + private final Parser parser; + private final boolean interactive; + + LuanParser(LuanSource source,UpValue.Getter envGetter) { + this.source = source; + this.frame = new Frame(envGetter); + this.parser = new Parser(source); + this.interactive = envGetter instanceof UpValue.ValueGetter; + } + + void addVar(String name,Object value) { + frame.addUpValueGetter(name,new UpValue.ValueGetter(value)); + } + + private LuanSource.Element se(int start) { + return new LuanSource.Element(source,start,parser.currentIndex()); + } + + private List<String> symbols() { + return frame.symbols; + } + + private int symbolsSize() { + return frame.symbols.size(); + } + + private void addSymbol(String name) { + frame.symbols.add(name); + if( frame.stackSize < symbolsSize() ) + frame.stackSize = symbolsSize(); + } + + private void addSymbols(List<String> names) { + frame.symbols.addAll(names); + if( frame.stackSize < symbolsSize() ) + frame.stackSize = symbolsSize(); + } + + private int stackIndex(String name) { + return frame.stackIndex(name); + } + + private void popSymbols(int n) { + List<String> symbols = frame.symbols; + while( n-- > 0 ) { + symbols.remove(symbols.size()-1); + } + } + + private int upValueIndex(String name) { + return frame.upValueIndex(name); + } + + private void incLoops() { + frame.loops++; + } + + private void decLoops() { + frame.loops--; + } + + private <T> T required(T t) throws ParseException { + if( t==null ) + throw parser.exception(); + return t; + } + + private <T> T required(T t,String msg) throws ParseException { + if( t==null ) + throw parser.exception(msg); + return t; + } + + private static Expr expr(Expressions exprs) { + if( exprs instanceof Expr ) + return (Expr)exprs; + return new ExpressionsExpr(exprs); + } + + private FnDef newFnDef(int start,Stmt stmt) { + return new FnDef( se(start), stmt, frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) ); + } + + FnDef Expression() throws ParseException { + Spaces(In.NOTHING); + int start = parser.begin(); + Expressions expr = Expr(In.NOTHING); + if( expr != null && parser.endOfInput() ) { + Stmt stmt = new ReturnStmt( se(start), expr ); + return parser.success(newFnDef(start,stmt)); + } + return parser.failure(null); + } + + FnDef RequiredModule() throws ParseException { + Spaces(In.NOTHING); + int start = parser.begin(); + frame.isVarArg = true; + Stmt stmt = RequiredBlock(); + if( parser.endOfInput() ) + return parser.success(newFnDef(start,stmt)); + throw parser.exception(); + } + + private Stmt RequiredBlock() throws ParseException { + List<Stmt> stmts = new ArrayList<Stmt>(); + int stackStart = symbolsSize(); + Stmt(stmts); + while( StmtSep(stmts) ) { + Spaces(In.NOTHING); + Stmt(stmts); + } + int stackEnd = symbolsSize(); + popSymbols( stackEnd - stackStart ); + if( stmts.isEmpty() ) + return Stmt.EMPTY; + if( stmts.size()==1 && stackStart==stackEnd ) + return stmts.get(0); + return new Block( stmts.toArray(new Stmt[0]), stackStart, stackEnd ); + } + + private boolean StmtSep(List<Stmt> stmts) throws ParseException { + parser.begin(); + if( parser.match( ';' ) ) + return parser.success(); + if( parser.match( "--" ) ) { + while( parser.noneOf("\r\n") ); + } + if( EndOfLine() ) + return parser.success(); + parser.rollback(); + Stmt stmt = TemplateStmt(); + if( stmt != null ) { + stmts.add(stmt); + return parser.success(); + } + return parser.failure(); + } + + private boolean EndOfLine() { + return parser.match( "\r\n" ) || parser.match( '\r' ) || parser.match( '\n' ); + } + + private void Stmt(List<Stmt> stmts) throws ParseException { + if( LocalStmt(stmts) ) + return; + Stmt stmt; + if( (stmt=ReturnStmt()) != null + || (stmt=FunctionStmt()) != null + || (stmt=LocalFunctionStmt()) != null + || (stmt=ImportStmt()) != null + || (stmt=BreakStmt()) != null + || (stmt=ForStmt()) != null + || (stmt=TryStmt()) != null + || (stmt=DoStmt()) != null + || (stmt=WhileStmt()) != null + || (stmt=FunctionStmt()) != null + || (stmt=RepeatStmt()) != null + || (stmt=IfStmt()) != null + || (stmt=SetStmt()) != null + || (stmt=ExpressionsStmt()) != null + ) { + stmts.add(stmt); + } + } + + private Stmt TemplateStmt() throws ParseException { + int start = parser.currentIndex(); + Expressions exp = TemplateExpressions(In.NOTHING); + if( exp == null ) + return null; + Expr fnExp = (Expr)nameVar(start,"Io").expr(); + fnExp = new IndexExpr( se(start), fnExp, new ConstExpr("stdout") ); + fnExp = new IndexExpr( se(start), fnExp, new ConstExpr("write") ); + FnCall fnCall = new FnCall( se(start), fnExp, exp ); + return new ExpressionsStmt(fnCall); + } + + private Expressions TemplateExpressions(In in) throws ParseException { + if( in.template ) + return null; + int start = parser.begin(); + if( !parser.match( "%>" ) ) + return parser.failure(null); + EndOfLine(); + In inTemplate = in.template(); + List<Expressions> builder = new ArrayList<Expressions>(); + while(true) { + if( parser.match( "<%=" ) ) { + Spaces(inTemplate); + builder.add( RequiredExpr(inTemplate) ); + RequiredMatch( "%>" ); + } else if( parser.match( "<%" ) ) { + Spaces(inTemplate); + return parser.success(ExpList.build(builder)); + } else { + int i = parser.currentIndex(); + do { + if( parser.match( "%>" ) ) + throw parser.exception("'%>' unexpected"); + if( !parser.anyChar() ) + throw parser.exception("Unclosed template expression"); + } while( !parser.test( "<%" ) ); + String match = parser.textFrom(i); + builder.add( new ConstExpr(match) ); + } + } + } + + private Stmt ReturnStmt() throws ParseException { + int start = parser.begin(); + if( !Keyword("return",In.NOTHING) ) + return parser.failure(null); + Expressions exprs = ExpList(In.NOTHING); + if( exprs==null ) + exprs = ExpList.emptyExpList; + return parser.success( new ReturnStmt(se(start),exprs) ); + } + + private Stmt FunctionStmt() throws ParseException { + parser.begin(); + if( !Keyword("function",In.NOTHING) ) + return parser.failure(null); + + int start = parser.currentIndex(); + Var var = nameVar(start,RequiredName(In.NOTHING)); + while( parser.match( '.' ) ) { + Spaces(In.NOTHING); + var = indexVar( start, expr(var.expr()), NameExpr(In.NOTHING) ); + } + Settable fnName = var.settable(); + + FnDef fnDef = RequiredFunction(In.NOTHING); + return parser.success( new SetStmt(fnName,fnDef) ); + } + + private Stmt LocalFunctionStmt() throws ParseException { + parser.begin(); + if( !(Keyword("local",In.NOTHING) && Keyword("function",In.NOTHING)) ) + return parser.failure(null); + String name = RequiredName(In.NOTHING); + addSymbol( name ); + FnDef fnDef = RequiredFunction(In.NOTHING); + return parser.success( new SetStmt( new SetLocalVar(symbolsSize()-1), fnDef ) ); + } + + private Stmt ImportStmt() throws ParseException { + int start = parser.begin(); + if( !Keyword("import",In.NOTHING) ) + return parser.failure(null); + Expr importExpr = (Expr)nameVar(start,"require").expr(); + String modName = StringLiteral(In.NOTHING); + if( modName==null ) + return parser.failure(null); + String varName = modName.substring(modName.lastIndexOf('.')+1); + LuanSource.Element se = se(start); + FnCall require = new FnCall( se, importExpr, new ConstExpr(modName) ); + Settable settable; + if( interactive ) { + settable = nameVar(se,varName).settable(); + } else { + addSymbol( varName ); + settable = new SetLocalVar(symbolsSize()-1); + } + return parser.success( new SetStmt( settable, expr(require) ) ); + } + + private Stmt BreakStmt() throws ParseException { + parser.begin(); + if( !Keyword("break",In.NOTHING) ) + return parser.failure(null); + if( frame.loops <= 0 ) + throw parser.exception("'break' outside of loop"); + return parser.success( new BreakStmt() ); + } + + private Stmt ForStmt() throws ParseException { + int start = parser.begin(); + int stackStart = symbolsSize(); + if( !Keyword("for",In.NOTHING) ) + return parser.failure(null); + List<String> names = RequiredNameList(In.NOTHING); + if( !Keyword("in",In.NOTHING) ) + return parser.failure(null); + Expr expr = expr(RequiredExpr(In.NOTHING)); + RequiredKeyword("do",In.NOTHING); + addSymbols(names); + Stmt loop = RequiredLoopBlock(); + RequiredKeyword("end",In.NOTHING); + Stmt stmt = new ForStmt( se(start), stackStart, symbolsSize() - stackStart, expr, loop ); + popSymbols( symbolsSize() - stackStart ); + return parser.success(stmt); + } + + private Stmt TryStmt() throws ParseException { + parser.begin(); + if( !Keyword("try",In.NOTHING) ) + return parser.failure(null); + Stmt tryBlock = RequiredBlock(); + RequiredKeyword("catch",In.NOTHING); + String name = RequiredName(In.NOTHING); + addSymbol(name); + RequiredKeyword("do",In.NOTHING); + Stmt catchBlock = RequiredBlock(); + RequiredKeyword("end",In.NOTHING); + Stmt stmt = new TryStmt( tryBlock, symbolsSize()-1, catchBlock ); + popSymbols(1); + return parser.success(stmt); + } + + private Stmt DoStmt() throws ParseException { + parser.begin(); + if( !Keyword("do",In.NOTHING) ) + return parser.failure(null); + Stmt stmt = RequiredBlock(); + RequiredKeyword("end",In.NOTHING); + return parser.success(stmt); + } + + private boolean LocalStmt(List<Stmt> stmts) throws ParseException { + parser.begin(); + if( !Keyword("local",In.NOTHING) ) + return parser.failure(); + List<String> names = NameList(In.NOTHING); + if( names==null ) + return parser.failure(); + if( parser.match( '=' ) ) { + Spaces(In.NOTHING); + Expressions values = ExpList(In.NOTHING); + if( values==null ) + throw parser.exception("Expressions expected"); + SetLocalVar[] vars = new SetLocalVar[names.size()]; + int stackStart = symbolsSize(); + for( int i=0; i<vars.length; i++ ) { + vars[i] = new SetLocalVar(stackStart+i); + } + stmts.add( new SetStmt( vars, values ) ); + } + addSymbols(names); + return parser.success(); + } + + private List<String> RequiredNameList(In in) throws ParseException { + parser.begin(); + List<String> names = NameList(in); + if( names==null ) + throw parser.exception("Name expected"); + return parser.success(names); + } + + private List<String> NameList(In in) throws ParseException { + String name = Name(in); + if( name==null ) + return null; + List<String> names = new ArrayList<String>(); + names.add(name); + while( (name=anotherName(in)) != null ) { + names.add(name); + } + return names; + } + + private String anotherName(In in) throws ParseException { + parser.begin(); + if( !parser.match( ',' ) ) + return parser.failure(null); + Spaces(in); + String name = Name(in); + if( name==null ) + return parser.failure(null); + return parser.success(name); + } + + private Stmt WhileStmt() throws ParseException { + int start = parser.begin(); + if( !Keyword("while",In.NOTHING) ) + return parser.failure(null); + Expr cnd = expr(RequiredExpr(In.NOTHING)); + RequiredKeyword("do",In.NOTHING); + Stmt loop = RequiredLoopBlock(); + RequiredKeyword("end",In.NOTHING); + return parser.success( new WhileStmt(se(start),cnd,loop) ); + } + + private Stmt RepeatStmt() throws ParseException { + int start = parser.begin(); + if( !Keyword("repeat",In.NOTHING) ) + return parser.failure(null); + Stmt loop = RequiredLoopBlock(); + RequiredKeyword("until",In.NOTHING); + Expr cnd = expr(RequiredExpr(In.NOTHING)); + return parser.success( new RepeatStmt(se(start),loop,cnd) ); + } + + private Stmt RequiredLoopBlock() throws ParseException { + incLoops(); + Stmt stmt = RequiredBlock(); + decLoops(); + return stmt; + } + + private Stmt IfStmt() throws ParseException { + parser.begin(); + if( !Keyword("if",In.NOTHING) ) + return parser.failure(null); + return parser.success( IfStmt2() ); + } + + private Stmt IfStmt2() throws ParseException { + int start = parser.currentIndex(); + Expr cnd = expr(RequiredExpr(In.NOTHING)); + RequiredKeyword("then",In.NOTHING); + Stmt thenBlock = RequiredBlock(); + Stmt elseBlock; + if( Keyword("elseif",In.NOTHING) ) { + elseBlock = IfStmt2(); + } else { + elseBlock = Keyword("else",In.NOTHING) ? RequiredBlock() : Stmt.EMPTY; + RequiredKeyword("end",In.NOTHING); + } + return new IfStmt(se(start),cnd,thenBlock,elseBlock); + } + + private Stmt SetStmt() throws ParseException { + parser.begin(); + List<Settable> vars = new ArrayList<Settable>(); + Settable s = SettableVar(); + if( s == null ) + return parser.failure(null); + vars.add(s); + while( parser.match( ',' ) ) { + Spaces(In.NOTHING); + s = SettableVar(); + if( s == null ) + return parser.failure(null); + vars.add(s); + } + if( !parser.match( '=' ) ) + return parser.failure(null); + Spaces(In.NOTHING); + Expressions values = ExpList(In.NOTHING); + if( values==null ) + throw parser.exception("Expressions expected"); + return parser.success( new SetStmt( vars.toArray(new Settable[0]), values ) ); + } + + private Stmt ExpressionsStmt() throws ParseException { + parser.begin(); + Expressions exp = Expr(In.NOTHING); + if( exp instanceof FnCall || exp instanceof AndExpr || exp instanceof OrExpr ) + return parser.success( new ExpressionsStmt(exp) ); + return parser.failure(null); + } + + private Settable SettableVar() throws ParseException { + int start = parser.begin(); + Var var = VarZ(In.NOTHING); + if( var==null ) + return parser.failure(null); + return parser.success( var.settable() ); + } + + private Expressions RequiredExpr(In in) throws ParseException { + parser.begin(); + return parser.success(required(Expr(in),"Bad expression")); + } + + private Expressions Expr(In in) throws ParseException { + parser.begin(); + Expressions exp; + return (exp = VarArgs(in)) != null + || (exp = OrExpr(in)) != null + ? parser.success(exp) + : parser.failure((Expressions)null) + ; + } + + private Expressions OrExpr(In in) throws ParseException { + int start = parser.begin(); + Expressions exp = AndExpr(in); + if( exp==null ) + return parser.failure(null); + while( Keyword("or",in) ) { + exp = new OrExpr( se(start), expr(exp), required(expr(AndExpr(in))) ); + } + return parser.success(exp); + } + + private Expressions AndExpr(In in) throws ParseException { + int start = parser.begin(); + Expressions exp = RelExpr(in); + if( exp==null ) + return parser.failure(null); + while( Keyword("and",in) ) { + exp = new AndExpr( se(start), expr(exp), required(expr(RelExpr(in))) ); + } + return parser.success(exp); + } + + private Expressions RelExpr(In in) throws ParseException { + int start = parser.begin(); + Expressions exp = ConcatExpr(in); + if( exp==null ) + return parser.failure(null); + while(true) { + if( parser.match("==") ) { + Spaces(in); + exp = new EqExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ); + } else if( parser.match("~=") ) { + Spaces(in); + exp = new NotExpr( se(start), new EqExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ) ); + } else if( parser.match("<=") ) { + Spaces(in); + exp = new LeExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ); + } else if( parser.match(">=") ) { + Spaces(in); + exp = new LeExpr( se(start), required(expr(ConcatExpr(in))), expr(exp) ); + } else if( parser.match("<") ) { + Spaces(in); + exp = new LtExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ); + } else if( parser.match(">") ) { + Spaces(in); + exp = new LtExpr( se(start), required(expr(ConcatExpr(in))), expr(exp) ); + } else + break; + } + return parser.success(exp); + } + + private Expressions ConcatExpr(In in) throws ParseException { + int start = parser.begin(); + Expressions exp = SumExpr(in); + if( exp==null ) + return parser.failure(null); + if( parser.match("..") ) { + Spaces(in); + exp = new ConcatExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ); + } + return parser.success(exp); + } + + private Expressions SumExpr(In in) throws ParseException { + int start = parser.begin(); + Expressions exp = TermExpr(in); + if( exp==null ) + return parser.failure(null); + while(true) { + if( parser.match('+') ) { + Spaces(in); + exp = new AddExpr( se(start), expr(exp), required(expr(TermExpr(in))) ); + } else if( Minus() ) { + Spaces(in); + exp = new SubExpr( se(start), expr(exp), required(expr(TermExpr(in))) ); + } else + break; + } + return parser.success(exp); + } + + private boolean Minus() { + parser.begin(); + return parser.match('-') && !parser.match('-') ? parser.success() : parser.failure(); + } + + private Expressions TermExpr(In in) throws ParseException { + int start = parser.begin(); + Expressions exp = UnaryExpr(in); + if( exp==null ) + return parser.failure(null); + while(true) { + if( parser.match('*') ) { + Spaces(in); + exp = new MulExpr( se(start), expr(exp), required(expr(UnaryExpr(in))) ); + } else if( parser.match('/') ) { + Spaces(in); + exp = new DivExpr( se(start), expr(exp), required(expr(UnaryExpr(in))) ); + } else if( Mod() ) { + Spaces(in); + exp = new ModExpr( se(start), expr(exp), required(expr(UnaryExpr(in))) ); + } else + break; + } + return parser.success(exp); + } + + private boolean Mod() { + parser.begin(); + return parser.match('%') && !parser.match('>') ? parser.success() : parser.failure(); + } + + private Expressions UnaryExpr(In in) throws ParseException { + int start = parser.begin(); + if( parser.match('#') ) { + Spaces(in); + return parser.success( new LenExpr( se(start), required(expr(UnaryExpr(in))) ) ); + } + if( Minus() ) { + Spaces(in); + return parser.success( new UnmExpr( se(start), required(expr(UnaryExpr(in))) ) ); + } + if( Keyword("not",in) ) { + Spaces(in); + return parser.success( new NotExpr( se(start), required(expr(UnaryExpr(in))) ) ); + } + Expressions exp = PowExpr(in); + if( exp==null ) + return parser.failure(null); + return parser.success(exp); + } + + private Expressions PowExpr(In in) throws ParseException { + int start = parser.begin(); + Expressions exp = SingleExpr(in); + if( exp==null ) + return parser.failure(null); + if( parser.match('^') ) { + Spaces(in); + exp = new ConcatExpr( se(start), expr(exp), required(expr(PowExpr(in))) ); + } + return parser.success(exp); + } + + private Expressions SingleExpr(In in) throws ParseException { + parser.begin(); + Expressions exp; + exp = FunctionExpr(in); + if( exp != null ) + return parser.success(exp); + exp = TableExpr(in); + if( exp != null ) + return parser.success(exp); + exp = VarExp(in); + if( exp != null ) + return parser.success(exp); + exp = Literal(in); + if( exp != null ) + return parser.success(exp); + return parser.failure(null); + } + + private Expr FunctionExpr(In in) throws ParseException { + if( !Keyword("function",in) ) + return null; + return RequiredFunction(in); + } + + private FnDef RequiredFunction(In in) throws ParseException { + int start = parser.begin(); + RequiredMatch('('); + In inParens = in.parens(); + Spaces(inParens); + frame = new Frame(frame); + List<String> names = NameList(in); + if( names != null ) { + addSymbols(names); + if( parser.match(',') ) { + Spaces(inParens); + if( !parser.match("...") ) + throw parser.exception(); + frame.isVarArg = true; + } + } else if( parser.match("...") ) { + Spaces(inParens); + frame.isVarArg = true; + } + RequiredMatch(')'); + Spaces(in); + Stmt block = RequiredBlock(); + RequiredKeyword("end",in); + FnDef fnDef = newFnDef(start,block); + frame = frame.parent; + return parser.success(fnDef); + } + + private VarArgs VarArgs(In in) throws ParseException { + int start = parser.begin(); + if( !frame.isVarArg || !parser.match("...") ) + return parser.failure(null); + Spaces(in); + return parser.success( new VarArgs(se(start)) ); + } + + private Expr TableExpr(In in) throws ParseException { + int start = parser.begin(); + if( !parser.match('{') ) + return parser.failure(null); + In inParens = in.parens(); + Spaces(inParens); + List<TableExpr.Field> fields = new ArrayList<TableExpr.Field>(); + List<Expressions> builder = new ArrayList<Expressions>(); + while( Field(fields,builder,in) && FieldSep(inParens) ); + Spaces(inParens); + if( !parser.match('}') ) + throw parser.exception("Expected table element or '}'"); + return parser.success( new TableExpr( se(start), fields.toArray(new TableExpr.Field[0]), ExpList.build(builder) ) ); + } + + private boolean FieldSep(In in) throws ParseException { + if( !parser.anyOf(",;") ) + return false; + Spaces(in); + return true; + } + + private boolean Field(List<TableExpr.Field> fields,List<Expressions> builder,In in) throws ParseException { + parser.begin(); + Expr exp = SubExpr(in); + if( exp==null ) + exp = NameExpr(in); + if( exp!=null && parser.match('=') ) { + Spaces(in); + fields.add( new TableExpr.Field( exp, required(expr(Expr(in))) ) ); + return parser.success(); + } + parser.rollback(); + Expressions exprs = Expr(in); + if( exprs != null ) { + builder.add(exprs); + return parser.success(); + } + return parser.failure(); + } + + private Expressions VarExp(In in) throws ParseException { + Var var = VarZ(in); + return var==null ? null : var.expr(); + } + + private Var VarZ(In in) throws ParseException { + int start = parser.begin(); + Var var = VarStart(in); + if( var==null ) + return parser.failure(null); + Var var2; + while( (var2=Var2(in,start,var.expr())) != null ) { + var = var2; + } + return parser.success(var); + } + + private Var Var2(In in,int start,Expressions exp1) throws ParseException { + parser.begin(); + Var var = VarExt(in,start,exp1); + if( var != null ) + return parser.success(var); + if( parser.match("->") ) { + Spaces(in); + List<Expressions> builder = new ArrayList<Expressions>(); + builder.add(exp1); + Expr exp2 = expr(RequiredVarExpB(in)); + FnCall fnCall = required(Args( in, start, exp2, builder )); + return parser.success(exprVar(fnCall)); + } + FnCall fnCall = Args( in, start, expr(exp1), new ArrayList<Expressions>() ); + if( fnCall != null ) + return parser.success(exprVar(fnCall)); + return parser.failure(null); + } + + private Expressions RequiredVarExpB(In in) throws ParseException { + int start = parser.begin(); + Var var = required(VarStart(in)); + Var var2; + while( (var2=VarExt(in,start,var.expr())) != null ) { + var = var2; + } + return parser.success(var.expr()); + } + + private Var VarExt(In in,int start,Expressions exp1) throws ParseException { + parser.begin(); + Expr exp2 = SubExpr(in); + if( exp2 != null ) + return parser.success(indexVar(start,expr(exp1),exp2)); + if( parser.match('.') ) { + Spaces(in); + exp2 = NameExpr(in); + if( exp2!=null ) + return parser.success(indexVar(start,expr(exp1),exp2)); + } + return parser.failure(null); + } + + private Var VarStart(In in) throws ParseException { + int start = parser.begin(); + if( parser.match('(') ) { + In inParens = in.parens(); + Spaces(inParens); + Expr exp = expr(RequiredExpr(inParens)); + RequiredMatch(')'); + Spaces(in); + return parser.success(exprVar(exp)); + } + String name = Name(in); + if( name != null ) + return parser.success(nameVar(start,name)); + return parser.failure(null); + } + + private Expr env() { + int index = stackIndex(_ENV); + if( index != -1 ) + return new GetLocalVar(null,index); + index = upValueIndex(_ENV); + if( index != -1 ) + return new GetUpVar(null,index); + throw new RuntimeException("_ENV not found"); + } + + private interface Var { + public Expressions expr(); + public Settable settable(); + } + + private Var nameVar(final int start,final String name) { + return nameVar(se(start),name); + } + + private Var nameVar(final LuanSource.Element se,final String name) { + return new Var() { + + public Expr expr() { + int index = stackIndex(name); + if( index != -1 ) + return new GetLocalVar(se,index); + index = upValueIndex(name); + if( index != -1 ) + return new GetUpVar(se,index); + return new IndexExpr( se, env(), new ConstExpr(name) ); + } + + public Settable settable() { + int index = stackIndex(name); + if( index != -1 ) + return new SetLocalVar(index); + index = upValueIndex(name); + if( index != -1 ) + return new SetUpVar(index); + return new SetTableEntry( se, env(), new ConstExpr(name) ); + } + }; + } + + private Var exprVar(final Expressions expr) { + return new Var() { + + public Expressions expr() { + return expr; + } + + public Settable settable() { + return null; + } + }; + } + + private Var indexVar(final int start,final Expr table,final Expr key) { + return new Var() { + + public Expr expr() { + return new IndexExpr( se(start), table, key ); + } + + public Settable settable() { + return new SetTableEntry(se(start),table,key); + } + }; + } + + private FnCall Args(In in,int start,Expr fn,List<Expressions> builder) throws ParseException { + parser.begin(); + return args(in,builder) + ? parser.success( new FnCall( se(start), fn, ExpList.build(builder) ) ) + : parser.failure((FnCall)null); + } + + private boolean args(In in,List<Expressions> builder) throws ParseException { + if( parser.match('(') ) { + In inParens = in.parens(); + Spaces(inParens); + ExpList(inParens,builder); // optional + if( !parser.match(')') ) + throw parser.exception("Expression or ')' expected"); + Spaces(in); + return true; + } + Expr exp = TableExpr(in); + if( exp != null ) { + builder.add(exp); + return true; + } + String s = StringLiteral(in); + if( s != null ) { + builder.add( new ConstExpr(s) ); + return true; + } + Expressions exps = TemplateExpressions(in); + if( exps != null ) { + builder.add(exps); + return true; + } + return false; + } + + private Expressions ExpList(In in) throws ParseException { + List<Expressions> builder = new ArrayList<Expressions>(); + return ExpList(in,builder) ? ExpList.build(builder) : null; + } + + private boolean ExpList(In in,List<Expressions> builder) throws ParseException { + parser.begin(); + Expressions exp = TemplateExpressions(in); + if( exp != null ) { + builder.add(exp); + return parser.success(); + } + exp = Expr(in); + if( exp==null ) + return parser.failure(); + builder.add(exp); + while( parser.match(',') ) { + Spaces(in); + exp = TemplateExpressions(in); + if( exp != null ) { + builder.add(exp); + return parser.success(); + } + builder.add( RequiredExpr(in) ); + } + return parser.success(); + } + + private Expr SubExpr(In in) throws ParseException { + parser.begin(); + if( !parser.match('[') ) + return parser.failure(null); + In inParens = in.parens(); + Spaces(inParens); + Expr exp = expr(RequiredExpr(inParens)); + RequiredMatch(']'); + Spaces(in); + return parser.success(exp); + } + + private Expr NameExpr(In in) throws ParseException { + String name = Name(in); + return name==null ? null : new ConstExpr(name); + } + + private String RequiredName(In in) throws ParseException { + parser.begin(); + String name = Name(in); + if( name==null ) + throw parser.exception("Name expected"); + return parser.success(name); + } + + private String Name(In in) throws ParseException { + int start = parser.begin(); + if( !NameFirstChar() ) + return parser.failure(null); + while( NameChar() ); + String match = parser.textFrom(start); + if( keywords.contains(match) ) + return parser.failure(null); + Spaces(in); + return parser.success(match); + } + + private boolean NameChar() { + return NameFirstChar() || Digit(); + } + + private boolean NameFirstChar() { + return parser.inCharRange('a', 'z') || parser.inCharRange('A', 'Z') || parser.match('_'); + } + + private void RequiredMatch(char c) throws ParseException { + if( !parser.match(c) ) + throw parser.exception("'"+c+"' expected"); + } + + private void RequiredMatch(String s) throws ParseException { + if( !parser.match(s) ) + throw parser.exception("'"+s+"' expected"); + } + + private void RequiredKeyword(String keyword,In in) throws ParseException { + if( !Keyword(keyword,in) ) + throw parser.exception("'"+keyword+"' expected"); + } + + private boolean Keyword(String keyword,In in) throws ParseException { + parser.begin(); + if( !parser.match(keyword) || NameChar() ) + return parser.failure(); + Spaces(in); + return parser.success(); + } + + private static final Set<String> keywords = new HashSet<String>(Arrays.asList( + "and", + "break", + "catch", + "do", + "else", + "elseif", + "end", + "false", + "for", + "function", + "goto", + "if", + "import", + "in", + "local", + "nil", + "not", + "or", + "repeat", + "return", + "then", + "true", + "try", + "until", + "while" + )); + + private Expr Literal(In in) throws ParseException { + if( NilLiteral(in) ) + return new ConstExpr(null); + Boolean b = BooleanLiteral(in); + if( b != null ) + return new ConstExpr(b); + Number n = NumberLiteral(in); + if( n != null ) + return new ConstExpr(n); + String s = StringLiteral(in); + if( s != null ) + return new ConstExpr(s); + return null; + } + + private boolean NilLiteral(In in) throws ParseException { + return Keyword("nil",in); + } + + private Boolean BooleanLiteral(In in) throws ParseException { + if( Keyword("true",in) ) + return true; + if( Keyword("false",in) ) + return false; + return null; + } + + private Number NumberLiteral(In in) throws ParseException { + parser.begin(); + Number n; + if( parser.matchIgnoreCase("0x") ) { + n = HexNumber(); + } else { + n = DecNumber(); + } + if( n==null || NameChar() ) + return parser.failure(null); + Spaces(in); + return parser.success(n); + } + + private Number DecNumber() { + int start = parser.begin(); + if( Int() ) { + if( parser.match('.') ) + Int(); // optional + } else if( parser.match('.') && Int() ) { + // ok + } else + return parser.failure(null); + Exponent(); // optional + return parser.success(Double.valueOf(parser.textFrom(start))); + } + + private boolean Exponent() { + parser.begin(); + if( !parser.matchIgnoreCase("e") ) + return parser.failure(); + parser.anyOf("+-"); // optional + if( !Int() ) + return parser.failure(); + return parser.success(); + } + + private boolean Int() { + if( !Digit() ) + return false; + while( Digit() ); + return true; + } + + private boolean Digit() { + return parser.inCharRange('0', '9'); + } + + private Number HexNumber() { + int start = parser.begin(); + double n; + if( HexInt() ) { + n = (double)Long.parseLong(parser.textFrom(start),16); + if( parser.match('.') ) { + start = parser.currentIndex(); + if( HexInt() ) { + String dec = parser.textFrom(start); + n += (double)Long.parseLong(dec,16) / Math.pow(16,dec.length()); + } + } + } else if( parser.match('.') && HexInt() ) { + String dec = parser.textFrom(start+1); + n = (double)Long.parseLong(dec,16) / Math.pow(16,dec.length()); + } else { + return parser.failure(null); + } + if( parser.matchIgnoreCase("p") ) { + parser.anyOf("+-"); // optional + start = parser.currentIndex(); + if( !HexInt() ) + return parser.failure(null); + n *= Math.pow(2,(double)Long.parseLong(parser.textFrom(start))); + } + return parser.success(Double.valueOf(n)); + } + + private boolean HexInt() { + if( !HexDigit() ) + return false; + while( HexDigit() ); + return true; + } + + + private boolean HexDigit() { + return Digit() || parser.anyOf("abcdefABCDEF"); + } + + private String StringLiteral(In in) throws ParseException { + String s; + if( (s=QuotedString('"'))==null + && (s=QuotedString('\''))==null + && (s=LongString())==null + ) + return null; + Spaces(in); + return s; + } + + private String LongString() throws ParseException { + parser.begin(); + if( !parser.match('[') ) + return parser.failure(null); + int start = parser.currentIndex(); + while( parser.match('=') ); + int nEquals = parser.currentIndex() - start; + if( !parser.match('[') ) + return parser.failure(null); + EndOfLine(); + start = parser.currentIndex(); + while( !LongBracketsEnd(nEquals) ) { + if( !parser.anyChar() ) + throw parser.exception("Unclosed long string"); + } + String s = parser.text.substring( start, parser.currentIndex() - nEquals - 2 ); + return parser.success(s); + } + + private String QuotedString(char quote) throws ParseException { + parser.begin(); + if( !parser.match(quote) ) + return parser.failure(null); + StringBuilder buf = new StringBuilder(); + while( !parser.match(quote) ) { + Character c = EscSeq(); + if( c != null ) { + buf.append(c); + } else { + if( !parser.anyChar() ) + throw parser.exception("Unclosed string"); + buf.append(parser.lastChar()); + } + } + return parser.success(buf.toString()); + } + + private Character EscSeq() { + parser.begin(); + if( !parser.match('\\') ) + return parser.failure(null); + if( parser.match('a') ) return parser.success('\u0007'); + if( parser.match('b') ) return parser.success('\b'); + if( parser.match('f') ) return parser.success('\f'); + if( parser.match('n') ) return parser.success('\n'); + if( parser.match('r') ) return parser.success('\r'); + if( parser.match('t') ) return parser.success('\t'); + if( parser.match('v') ) return parser.success('\u000b'); + if( parser.match('\\') ) return parser.success('\\'); + if( parser.match('"') ) return parser.success('"'); + if( parser.match('\'') ) return parser.success('\''); + int start = parser.currentIndex(); + if( parser.match('x') && HexDigit() && HexDigit() ) + return parser.success((char)Integer.parseInt(parser.textFrom(start+1),16)); + if( Digit() ) { + if( Digit() ) Digit(); // optional + return parser.success((char)Integer.parseInt(parser.textFrom(start))); + } + return parser.failure(null); + } + + private void Spaces(In in) throws ParseException { + while( parser.anyOf(" \t") || Comment() || ContinueOnNextLine() || in.parens && NewLine() ); + } + + private boolean ContinueOnNextLine() { + parser.begin(); + return parser.match('\\') && EndOfLine() ? parser.success() : parser.failure(); + } + + private boolean NewLine() { + if( !EndOfLine() ) + return false; + if( parser.match("--") ) { + while( parser.noneOf("\r\n") ); + } + return true; + } + + private boolean Comment() throws ParseException { + parser.begin(); + if( !parser.match("--[") ) + return parser.failure(); + int start = parser.currentIndex(); + while( parser.match('=') ); + int nEquals = parser.currentIndex() - start; + if( !parser.match('[') ) + return parser.failure(); + while( !LongBracketsEnd(nEquals) ) { + if( !parser.anyChar() ) + throw parser.exception("Unclosed comment"); + } + return parser.success(); + } + + private boolean LongBracketsEnd(int nEquals) { + parser.begin(); + if( !parser.match(']') ) + return parser.failure(); + while( nEquals-- > 0 ) { + if( !parser.match('=') ) + return parser.failure(); + } + if( !parser.match(']') ) + return parser.failure(); + return parser.success(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/LuanStateImpl.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,137 @@ +package luan.impl; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import luan.Luan; +import luan.LuanState; +import luan.LuanTable; +import luan.LuanFunction; +import luan.MetatableGetter; +import luan.LuanException; +import luan.LuanElement; +import luan.DeepCloner; + + +final class LuanStateImpl extends LuanState { + + private static class Frame { + final Frame previousFrame; + final Closure closure; + final Object[] stack; + final Object[] varArgs; + UpValue[] downValues = null; + + Frame( Frame previousFrame, Closure closure, int stackSize, Object[] varArgs) { + this.previousFrame = previousFrame; + this.closure = closure; + this.stack = new Object[stackSize]; + this.varArgs = varArgs; + } + + void stackClear(int start,int end) { + if( downValues != null ) { + for( int i=start; i<end; i++ ) { + UpValue downValue = downValues[i]; + if( downValue != null ) { + downValue.close(); + downValues[i] = null; + } + } + } + for( int i=start; i<end; i++ ) { + stack[i] = null; + } + } + + UpValue getUpValue(int index) { + if( downValues==null ) + downValues = new UpValue[stack.length]; + if( downValues[index] == null ) + downValues[index] = new UpValue(stack,index); + return downValues[index]; + } + } + + private Frame frame = null; + Object returnValues; + Closure tailFn; + Map<UpValue.EnvGetter,UpValue> envs = new HashMap<UpValue.EnvGetter,UpValue>(); + + LuanStateImpl() {} + + private LuanStateImpl(LuanStateImpl luan) { + super(luan); + } + + @Override public LuanState shallowClone() { +// if( frame != null ) +// throw new IllegalStateException("frame isn't null"); + return new LuanStateImpl(this); + } + + @Override public void deepenClone(LuanState clone,DeepCloner cloner) { + super.deepenClone(clone,cloner); + LuanStateImpl cloneImpl = (LuanStateImpl)clone; + cloneImpl.envs = new HashMap<UpValue.EnvGetter,UpValue>(); + for( Map.Entry<UpValue.EnvGetter,UpValue> entry : envs.entrySet() ) { + cloneImpl.envs.put( entry.getKey(), cloner.deepClone(entry.getValue()) ); + } + } + + // returns stack + Object[] newFrame(Closure closure, int stackSize, Object[] varArgs) { + returnValues = LuanFunction.NOTHING; + tailFn = null; + frame = new Frame(frame,closure,stackSize,varArgs); + return frame.stack; + } + + void popFrame() { + returnValues = LuanFunction.NOTHING; + tailFn = null; + frame = frame.previousFrame; + } + + Object stackGet(int index) { + return frame.stack[index]; + } + + void stackSet(int index,Object value) { + frame.stack[index] = value; + } + + void stackClear(int start,int end) { + frame.stackClear(start,end); + } + + Object[] varArgs() { + return frame.varArgs; + } + + Closure closure() { + return frame.closure; + } + + UpValue getUpValue(int index) { + return frame.getUpValue(index); + } + + UpValue getUpValue(UpValue.EnvGetter getter) throws LuanException { + UpValue uv = envs.get(getter); + if( uv == null ) { + LuanTable env = new LuanTable(); + uv = new UpValue(env); + envs.put(getter,uv); + } + return uv; + } + + @Override public LuanTable currentEnvironment() { + if( frame==null ) + return null; + return (LuanTable)frame.closure.upValues()[0].get(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/ModExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,23 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class ModExpr extends BinaryOpExpr { + + ModExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object o1 = op1.eval(luan); + Object o2 = op2.eval(luan); + Number n1 = Luan.toNumber(o1); + Number n2 = Luan.toNumber(o2); + if( n1 != null && n2 != null ) + return n1.doubleValue() % n2.doubleValue(); + return arithmetic(luan,"__mod",o1,o2); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/MulExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,23 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class MulExpr extends BinaryOpExpr { + + MulExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object o1 = op1.eval(luan); + Object o2 = op2.eval(luan); + Number n1 = Luan.toNumber(o1); + Number n2 = Luan.toNumber(o2); + if( n1 != null && n2 != null ) + return n1.doubleValue() * n2.doubleValue(); + return arithmetic(luan,"__mul",o1,o2); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/NotExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,17 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class NotExpr extends UnaryOpExpr { + + NotExpr(LuanSource.Element se,Expr op) { + super(se,op); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + return !Luan.toBoolean(op.eval(luan)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/OrExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,18 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class OrExpr extends BinaryOpExpr { + + OrExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object v1 = op1.eval(luan); + return Luan.toBoolean(v1) ? v1 : op2.eval(luan); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/ParseException.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,55 @@ +package luan.impl; + +import luan.LuanSource; + + +public final class ParseException extends Exception { + public final LuanSource src; + public final int iCurrent; + public final int iHigh; + + ParseException(String msg,LuanSource src,int iCurrent,int iHigh) { + super(msg); + this.src = src; + this.iCurrent = iCurrent; + this.iHigh = iHigh; +//System.out.println("iCurrent = "+iCurrent); +//System.out.println("iHigh = "+iHigh); + } + + private class Location { + final int line; + final int pos; + + Location(int index) { + int line = 0; + int i = -1; + while(true) { + int j = src.text.indexOf('\n',i+1); + if( j == -1 || j >= index ) + break; + i = j; + line++; + } + this.line = line; + this.pos = index - i - 1; + } + } + + private String[] lines() { + return src.text.split("\n",-1); + } + + public String getFancyMessage() { + Location loc = new Location(iCurrent); + String line = lines()[loc.line]; + String msg = getMessage() + " (line " + (loc.line+1) + ", pos " + (loc.pos+1) + ") in " + src.name + "\n"; + StringBuilder sb = new StringBuilder(msg); + sb.append( line + "\n" ); + for( int i=0; i<loc.pos; i++ ) { + sb.append( line.charAt(i)=='\t' ? '\t' : ' ' ); + } + sb.append("^\n"); + return sb.toString(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/Parser.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,152 @@ +package luan.impl; + +import luan.LuanSource; + + +final class Parser { + private final LuanSource src; + public final String text; + private final int len; + private int[] stack = new int[256]; + private int frame = 0; + private int iHigh; + + public Parser(LuanSource src) { + this.src = src; + this.text = src.text; + this.len = text.length(); + } + + private int i() { + return stack[frame]; + } + + private void i(int i) { + stack[frame] += i; + if( iHigh < stack[frame] ) + iHigh = stack[frame]; + } + + public int begin() { + frame++; + if( frame == stack.length ) { + int[] a = new int[2*frame]; + System.arraycopy(stack,0,a,0,frame); + stack = a; + } + stack[frame] = stack[frame-1]; + return i(); + } + + public void rollback() { + stack[frame] = stack[frame-1]; + } + + public <T> T success(T t) { + success(); + return t; + } + + public boolean success() { + frame--; + stack[frame] = stack[frame+1]; + return true; + } + + public <T> T failure(T t) { + failure(); + return t; + } + + public boolean failure() { + frame--; + return false; + } + + public ParseException exception(String msg) { + return new ParseException(msg,src,i(),iHigh); + } + + public ParseException exception() { + return exception("Invalid input"); + } + + public int currentIndex() { + return i(); + } + + public char lastChar() { + return text.charAt(i()-1); + } + + public char currentChar() { + return text.charAt(i()); + } + + public boolean endOfInput() { + return i() >= len; + } + + public boolean match(char c) { + if( endOfInput() || text.charAt(i()) != c ) + return false; + i(1); + return true; + } + + public boolean match(String s) { + int n = s.length(); + if( !text.regionMatches(i(),s,0,n) ) + return false; + i(n); + return true; + } + + public boolean matchIgnoreCase(String s) { + int n = s.length(); + if( !text.regionMatches(true,i(),s,0,n) ) + return false; + i(n); + return true; + } + + public boolean anyOf(String s) { + if( endOfInput() || s.indexOf(text.charAt(i())) == -1 ) + return false; + i(1); + return true; + } + + public boolean noneOf(String s) { + if( endOfInput() || s.indexOf(text.charAt(i())) != -1 ) + return false; + i(1); + return true; + } + + public boolean inCharRange(char cLow, char cHigh) { + if( endOfInput() ) + return false; + char c = text.charAt(i()); + if( !(cLow <= c && c <= cHigh) ) + return false; + i(1); + return true; + } + + public boolean anyChar() { + if( endOfInput() ) + return false; + i(1); + return true; + } + + public boolean test(String s) { + return text.regionMatches(i(),s,0,s.length()); + } + + public String textFrom(int start) { + return text.substring(start,i()); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/PowExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,23 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class PowExpr extends BinaryOpExpr { + + PowExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object o1 = op1.eval(luan); + Object o2 = op2.eval(luan); + Number n1 = Luan.toNumber(o1); + Number n2 = Luan.toNumber(o2); + if( n1 != null && n2 != null ) + return Math.pow( n1.doubleValue(), n2.doubleValue() ); + return arithmetic(luan,"__pow",o1,o2); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/RepeatStmt.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,25 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class RepeatStmt extends CodeImpl implements Stmt { + private final Stmt doStmt; + private final Expr cnd; + + RepeatStmt(LuanSource.Element se,Stmt doStmt,Expr cnd) { + super(se); + this.doStmt = doStmt; + this.cnd = cnd; + } + + @Override public void eval(LuanStateImpl luan) throws LuanException { + try { + do { + doStmt.eval(luan); + } while( !luan.bit(se).checkBoolean( cnd.eval(luan) ) ); + } catch(BreakException e) {} + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/ReturnException.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,4 @@ +package luan.impl; + + +final class ReturnException extends RuntimeException {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/ReturnStmt.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,39 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanFunction; +import luan.LuanSource; + + +final class ReturnStmt extends CodeImpl implements Stmt { + private final Expressions expressions; + private final Expr tailFnExpr; + boolean throwReturnException = true; + + ReturnStmt(LuanSource.Element se,Expressions expressions) { + super(se); + if( expressions instanceof FnCall ) { // tail call + FnCall fnCall = (FnCall)expressions; + this.expressions = fnCall.args; + this.tailFnExpr = fnCall.fnExpr; + } else { + this.expressions = expressions; + this.tailFnExpr = null; + } + } + + @Override public void eval(LuanStateImpl luan) throws LuanException { + luan.returnValues = expressions.eval(luan); + if( tailFnExpr != null ) { + LuanFunction tailFn = luan.bit(se).checkFunction( tailFnExpr.eval(luan) ); + if( tailFn instanceof Closure ) { + luan.tailFn = (Closure)tailFn; + } else { + luan.returnValues = luan.bit(tailFnExpr.se()).call(tailFn,tailFnExpr.se().text(),Luan.array(luan.returnValues)); + } + } + if( throwReturnException ) + throw new ReturnException(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/SetLocalVar.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,14 @@ +package luan.impl; + + +final class SetLocalVar implements Settable { + private final int index; + + SetLocalVar(int index) { + this.index = index; + } + + @Override public void set(LuanStateImpl luan,Object value) { + luan.stackSet( index, value ); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/SetStmt.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,36 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; + + +final class SetStmt implements Stmt { + private final Settable[] vars; + private final Expressions expressions; + + SetStmt(Settable var,Expr expr) { + this( new Settable[]{var}, expr ); + } + + SetStmt(Settable[] vars,Expressions expressions) { + this.vars = vars; + this.expressions = expressions; + } + + @Override public void eval(LuanStateImpl luan) throws LuanException { + final Object obj = expressions.eval(luan); + if( obj instanceof Object[] ) { + Object[] vals = (Object[])obj; + for( int i=0; i<vars.length; i++ ) { + Object val = i < vals.length ? vals[i] : null; + vars[i].set(luan,val); + } + } else { + vars[0].set(luan,obj); + for( int i=1; i<vars.length; i++ ) { + vars[i].set(luan,null); + } + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/SetTableEntry.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,48 @@ +package luan.impl; + +import luan.LuanException; +import luan.LuanTable; +import luan.Luan; +import luan.LuanFunction; +import luan.LuanSource; + + +final class SetTableEntry extends CodeImpl implements Settable { + private final Expr tableExpr; + private final Expr keyExpr; + + SetTableEntry(LuanSource.Element se,Expr tableExpr,Expr keyExpr) { + super(se); + this.tableExpr = tableExpr; + this.keyExpr = keyExpr; + } + + @Override public void set(LuanStateImpl luan,Object value) throws LuanException { + newindex( luan, tableExpr.eval(luan), keyExpr.eval(luan), value ); + } + + private void newindex(LuanStateImpl luan,Object t,Object key,Object value) throws LuanException { + Object h; + if( t instanceof LuanTable ) { + LuanTable table = (LuanTable)t; + Object old = table.put(key,value); + if( old != null ) + return; + h = luan.getHandler("__newindex",t); + if( h==null ) + return; + table.put(key,old); + } else { + h = luan.getHandler("__newindex",t); + if( h==null ) + throw luan.bit(se).exception( "attempt to index a " + Luan.type(t) + " value" ); + } + if( h instanceof LuanFunction ) { + LuanFunction fn = (LuanFunction)h; + luan.bit(se).call(fn,"__newindex",new Object[]{t,key,value}); + return; + } + newindex(luan,h,key,value); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/SetUpVar.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,14 @@ +package luan.impl; + + +final class SetUpVar implements Settable { + private final int index; + + SetUpVar(int index) { + this.index = index; + } + + @Override public void set(LuanStateImpl luan,Object value) { + luan.closure().upValues()[index].set(value); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/Settable.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,8 @@ +package luan.impl; + +import luan.LuanException; + + +interface Settable { + public void set(LuanStateImpl luan,Object value) throws LuanException; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/Stmt.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,12 @@ +package luan.impl; + +import luan.LuanException; + + +interface Stmt { + public void eval(LuanStateImpl luan) throws LuanException; + + static final Stmt EMPTY = new Stmt() { + @Override public void eval(LuanStateImpl luan) {} + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/SubExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,23 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class SubExpr extends BinaryOpExpr { + + SubExpr(LuanSource.Element se,Expr op1,Expr op2) { + super(se,op1,op2); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object o1 = op1.eval(luan); + Object o2 = op2.eval(luan); + Number n1 = Luan.toNumber(o1); + Number n2 = Luan.toNumber(o2); + if( n1 != null && n2 != null ) + return n1.doubleValue() - n2.doubleValue(); + return arithmetic(luan,"__sub",o1,o2); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/TableExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,45 @@ +package luan.impl; + +import luan.LuanException; +import luan.LuanTable; +import luan.LuanSource; + + +final class TableExpr extends CodeImpl implements Expr { + + static class Field { + final Expr key; + final Expr value; + + Field(Expr key,Expr value) { + this.key = key; + this.value = value; + } + } + + private final Field[] fields; + private final Expressions expressions; + + TableExpr(LuanSource.Element se,Field[] fields,Expressions expressions) { + super(se); + this.fields = fields; + this.expressions = expressions; + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + LuanTable table = new LuanTable(); + for( Field field : fields ) { + table.put( field.key.eval(luan), field.value.eval(luan) ); + } + Object obj = expressions.eval(luan); + if( obj instanceof Object[] ) { + Object[] a = (Object[])obj; + for( int i=0; i<a.length; i++ ) { + table.put( i+1, a[i] ); + } + } else { + table.put( 1, obj ); + } + return table; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/TryStmt.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,30 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; + + +final class TryStmt implements Stmt { + private final Stmt tryBlock; + private final int iExceptionVar; + private final Stmt catchBlock; + + TryStmt(Stmt tryBlock,int iExceptionVar,Stmt catchBlock) { + this.tryBlock = tryBlock; + this.iExceptionVar = iExceptionVar; + this.catchBlock = catchBlock; + } + + @Override public void eval(LuanStateImpl luan) throws LuanException { + try { + tryBlock.eval(luan); + } catch(LuanException e) { + try { + luan.stackSet( iExceptionVar, e ); + catchBlock.eval(luan); + } finally { + luan.stackClear(iExceptionVar,iExceptionVar+1); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/UnaryOpExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,13 @@ +package luan.impl; + +import luan.LuanSource; + + +abstract class UnaryOpExpr extends CodeImpl implements Expr { + final Expr op; + + UnaryOpExpr(LuanSource.Element se,Expr op) { + super(se); + this.op = op; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/UnmExpr.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,29 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanFunction; +import luan.LuanException; +import luan.LuanSource; +import luan.LuanBit; + + +// unary minus +final class UnmExpr extends UnaryOpExpr { + + UnmExpr(LuanSource.Element se,Expr op) { + super(se,op); + } + + @Override public Object eval(LuanStateImpl luan) throws LuanException { + Object o = op.eval(luan); + Number n = Luan.toNumber(o); + if( n != null ) + return -n.doubleValue(); + LuanBit bit = luan.bit(se); + LuanFunction fn = bit.getHandlerFunction("__unm",o); + if( fn != null ) { + return Luan.first(bit.call(fn,"__unm",new Object[]{o})); + } + throw bit.exception("attempt to perform arithmetic on a "+Luan.type(o)+" value"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/UpValue.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,105 @@ +package luan.impl; + +import luan.DeepCloner; +import luan.DeepCloneable; +import luan.LuanException; + + +final class UpValue implements DeepCloneable<UpValue> { + private Object[] stack; + private int index; + private boolean isClosed = false; + private Object value; + + UpValue(Object[] stack,int index) { + this.stack = stack; + this.index = index; + } + + UpValue(Object value) { + this.value = value; + this.isClosed = true; + } + + private UpValue() {} + + @Override public UpValue shallowClone() { + return new UpValue(); + } + + @Override public void deepenClone(UpValue clone,DeepCloner cloner) { + clone.isClosed = isClosed; + if( isClosed ) { + clone.value = cloner.get(value); + } else { + clone.stack = cloner.deepClone(stack); + clone.index = index; + } + } + + Object get() { + return isClosed ? value : stack[index]; + } + + void set(Object value) { + if( isClosed ) { + this.value = value; + } else { + stack[index] = value; + } + } + + void close() { + value = stack[index]; + isClosed = true; + stack = null; + } + + static interface Getter { + public UpValue get(LuanStateImpl luan) throws LuanException; + } + + static final class StackGetter implements Getter { + private final int index; + + StackGetter(int index) { + this.index = index; + } + + public UpValue get(LuanStateImpl luan) { + return luan.getUpValue(index); + } + } + + static final class NestedGetter implements Getter { + private final int index; + + NestedGetter(int index) { + this.index = index; + } + + public UpValue get(LuanStateImpl luan) { + return luan.closure().upValues()[index]; + } + } + + static final class EnvGetter implements Getter { + + public UpValue get(LuanStateImpl luan) throws LuanException { + return luan.getUpValue(this); + } + } + + static final class ValueGetter implements Getter { + private final UpValue upValue; + + ValueGetter(Object value) { + this.upValue = new UpValue(value); + } + + public UpValue get(LuanStateImpl luan) { + return upValue; + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/VarArgs.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,15 @@ +package luan.impl; + +import luan.LuanSource; + + +final class VarArgs extends CodeImpl implements Expressions { + + VarArgs(LuanSource.Element se) { + super(se); + } + + @Override public Object[] eval(LuanStateImpl luan) { + return luan.varArgs(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/WhileStmt.java Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,25 @@ +package luan.impl; + +import luan.Luan; +import luan.LuanException; +import luan.LuanSource; + + +final class WhileStmt extends CodeImpl implements Stmt { + private final Expr cnd; + private final Stmt doStmt; + + WhileStmt(LuanSource.Element se,Expr cnd,Stmt doStmt) { + super(se); + this.cnd = cnd; + this.doStmt = doStmt; + } + + @Override public void eval(LuanStateImpl luan) throws LuanException { + try { + while( luan.bit(se).checkBoolean( cnd.eval(luan) ) ) { + doStmt.eval(luan); + } + } catch(BreakException e) {} + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/init.luan Sun Jun 22 05:41:22 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")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/modules/BasicLuan.java Sun Jun 22 05:41:22 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 BasicLuan { + + 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(BasicLuan.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(BasicLuan.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)) : IoLuan.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/core/src/luan/modules/BinaryLuan.java Sun Jun 22 05:41:22 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 BinaryLuan { + + 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(BinaryLuan.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/core/src/luan/modules/HtmlLuan.java Sun Jun 22 05:41:22 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 HtmlLuan { + + 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(HtmlLuan.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/core/src/luan/modules/IoLuan.java Sun Jun 22 05:41:22 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 IoLuan { + + 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( + IoLuan.class.getMethod( "stdin_read_text" ), null + ) ); + stdin.put( "read_binary", new LuanJavaFunction( + IoLuan.class.getMethod( "stdin_read_binary" ), null + ) ); + stdin.put( "read_lines", new LuanJavaFunction( + IoLuan.class.getMethod( "stdin_read_lines" ), null + ) ); + stdin.put( "read_blocks", new LuanJavaFunction( + IoLuan.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(IoLuan.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 IoLuan() {} // never +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/modules/JavaLuan.java Sun Jun 22 05:41:22 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 JavaLuan { + + 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(JavaLuan.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 = JavaLuan.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(JavaLuan.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/core/src/luan/modules/MathLuan.java Sun Jun 22 05:41:22 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 MathLuan { + + 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(MathLuan.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/core/src/luan/modules/PackageLuan.java Sun Jun 22 05:41:22 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 PackageLuan { + + private static final String jpath = "luan.modules.?Luan.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(PackageLuan.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 = BasicLuan.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/core/src/luan/modules/PickleClient.java Sun Jun 22 05:41:22 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/core/src/luan/modules/PickleCon.java Sun Jun 22 05:41:22 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 = BasicLuan.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/core/src/luan/modules/PickleServer.java Sun Jun 22 05:41:22 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/core/src/luan/modules/Reactionary.luan Sun Jun 22 05:41:22 2014 +0000 @@ -0,0 +1,22 @@ +-- Reactionary + +host = "localhost" +port = 9101 + +function put_site(domain,password,dir) + local pc = Io.Socket(host,port).Pickle_client() + local pickle = pc.pickle + pc.call %> + Reactionary.do_put_site(<%=pickle(domain)%>,<%=pickle(password)%>,<%=pickle(dir)%>) + <% + pc.close() +end + +function delete_site(domain,password) + local pc = Io.Socket(host,port).Pickle_client() + local pickle = pc.pickle + pc.call %> + Reactionary.do_delete_site(<%=pickle(domain)%>,<%=pickle(password)%>) + <% + pc.close() +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/modules/StringLuan.java Sun Jun 22 05:41:22 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); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/modules/TableLuan.java Sun Jun 22 05:41:22 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 TableLuan { + + 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(TableLuan.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/core/src/luan/modules/ThreadLuan.java Sun Jun 22 05:41:22 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 ThreadLuan { + + 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(ThreadLuan.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/core/src/luan/modules/Utils.java Sun Jun 22 05:41:22 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; + } +}
--- a/src/luan/DeepCloneable.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -package luan; - - -public interface DeepCloneable<T extends DeepCloneable> { - public T shallowClone(); - public void deepenClone(T clone,DeepCloner cloner); -}
--- a/src/luan/DeepCloner.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -package luan; - -import java.util.Map; -import java.util.IdentityHashMap; - - -public final class DeepCloner { - private final Map<Object,Object> cloned = new IdentityHashMap<Object,Object>(); - - public <T extends DeepCloneable<T>> T deepClone(T obj) { - @SuppressWarnings("unchecked") - T rtn = (T)cloned.get(obj); - if( rtn == null ) { - rtn = obj.shallowClone(); - cloned.put(obj,rtn); - obj.deepenClone(rtn,this); - } - return rtn; - } - - public <T> T[] deepClone(T[] obj) { - if( obj.length == 0 ) - return obj; - @SuppressWarnings("unchecked") - T[] rtn = (T[])cloned.get(obj); - if( rtn == null ) { - rtn = obj.clone(); - cloned.put(obj,rtn); - for( int i=0; i<rtn.length; i++ ) { - @SuppressWarnings("unchecked") - T t = get(rtn[i]); - rtn[i] = t; - } - } - return rtn; - } - - public <T> T get(T obj) { - if( !(obj instanceof DeepCloneable) ) - return obj; - @SuppressWarnings("unchecked") - T dc = (T)deepClone((DeepCloneable)obj); - return dc; - } -}
--- a/src/luan/Luan.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -package luan; - -import luan.modules.BasicLuan; - - -public final class Luan { - public static final String version = "Luan 0.1"; - - public static void main(String[] args) { - LuanState luan = LuanState.newStandard(); - try { - LuanFunction standalone = (LuanFunction)BasicLuan.load_file(luan,"java:luan/cmd_line.luan"); - luan.call(standalone,args); - } catch(LuanException e) { - System.err.println(e.getMessage()); -// e.printStackTrace(); - System.exit(-1); - } - } - - public static Object first(Object obj) { - if( !(obj instanceof Object[]) ) - return obj; - Object[] a = (Object[])obj; - return a.length==0 ? null : a[0]; - } - - public static Object[] array(Object obj) { - return obj instanceof Object[] ? (Object[])obj : new Object[]{obj}; - } - - public static String type(Object obj) { - if( obj == null ) - return "nil"; - if( obj instanceof String ) - return "string"; - if( obj instanceof Boolean ) - return "boolean"; - if( obj instanceof Number ) - return "number"; - if( obj instanceof LuanTable ) - return "table"; - if( obj instanceof LuanFunction ) - return "function"; - if( obj instanceof byte[] ) - return "binary"; - return "userdata"; - } - - public static boolean toBoolean(Object obj) { - return obj != null && !Boolean.FALSE.equals(obj); - } - - public static String asString(Object obj) { - if( obj instanceof String ) - return (String)obj; - if( obj instanceof Number ) - return toString((Number)obj); - return null; - } - - public static Number toNumber(Object obj) { - return toNumber(obj,null); - } - - public static Number toNumber(Object obj,Integer base) { - if( obj instanceof Number ) - return (Number)obj; - if( obj instanceof String ) { - String s = (String)obj; - try { - if( base==null ) - return Double.valueOf(s); - else - return Long.valueOf(s,base); - } catch(NumberFormatException e) {} - } - return null; - } - - public static String toString(Number n) { - if( n instanceof Integer ) - return n.toString(); - String s = n.toString(); - int iE = s.indexOf('E'); - String ending = null; - if( iE != -1 ) { - ending = s.substring(iE); - s = s.substring(0,iE); - } - if( s.endsWith(".0") ) - s = s.substring(0,s.length()-2); - if( ending != null ) - s += ending; - return s; - } - - public static Integer asInteger(Object obj) { - if( obj instanceof Integer ) - return (Integer)obj; - if( !(obj instanceof Number) ) - return null; - Number n = (Number)obj; - int i = n.intValue(); - return i==n.doubleValue() ? Integer.valueOf(i) : null; - } - - public static String toString(Object obj) { - if( obj == null ) - return "nil"; - if( obj instanceof Number ) - return Luan.toString((Number)obj); - if( obj instanceof LuanException ) { - LuanException le = (LuanException)obj; - return le.getMessage(); - } - if( obj instanceof byte[] ) - return "binary: " + Integer.toHexString(obj.hashCode()); - return obj.toString(); - } - - public static String stringEncode(String s) { - s = s.replace("\\","\\\\"); - s = s.replace("\u0007","\\a"); - s = s.replace("\b","\\b"); - s = s.replace("\f","\\f"); - s = s.replace("\n","\\n"); - s = s.replace("\r","\\r"); - s = s.replace("\t","\\t"); - s = s.replace("\u000b","\\v"); - s = s.replace("\"","\\\""); - return s; - } - - public static String repr(Object obj) { - 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 "\"" + stringEncode((String)obj) + "\""; - if( obj instanceof LuanRepr ) - return ((LuanRepr)obj).repr(); - return null; - } - - private Luan() {} // never -}
--- a/src/luan/LuanBit.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -package luan; - -import java.util.List; - - -public final class LuanBit { - public final LuanState luan; - public final LuanElement el; - - LuanBit(LuanState luan,LuanElement el) { - this.luan = luan; - this.el = el; - } - - public LuanException exception(Object msg) { - return new LuanException(this,msg); - } - - public String stackTrace() { - StringBuilder buf = new StringBuilder(); - LuanElement el = this.el; - for( int i = luan.stackTrace.size() - 1; i>=0; i-- ) { - StackTraceElement stackTraceElement = luan.stackTrace.get(i); - buf.append( "\n\t" ).append( el.toString(stackTraceElement.fnName) ); - el = stackTraceElement.call; - } - return buf.toString(); - } - - public void dumpStack() { - System.err.println( stackTrace() ); - } - - public Object call(LuanFunction fn,String fnName,Object[] args) throws LuanException { - List<StackTraceElement> stackTrace = luan.stackTrace; - stackTrace.add( new StackTraceElement(el,fnName) ); - try { - return fn.call(luan,args); - } finally { - stackTrace.remove(stackTrace.size()-1); - } - } - - public String checkString(Object obj) throws LuanException { - String s = Luan.asString(obj); - if( s == null ) - throw exception( "attempt to use a " + Luan.type(obj) + " as a string" ); - return s; - } - - public Number checkNumber(Object obj) throws LuanException { - Number n = Luan.toNumber(obj); - if( n == null ) - throw exception( "attempt to perform arithmetic on a " + Luan.type(obj) + " value" ); - return n; - } - - public LuanFunction checkFunction(Object obj) throws LuanException { - if( obj instanceof LuanFunction ) - return (LuanFunction)obj; - throw exception( "attempt to call a " + Luan.type(obj) + " value" ); - } - - public Boolean checkBoolean(Object obj) throws LuanException { - if( obj instanceof Boolean ) - return (Boolean)obj; - throw exception( "attempt to use a " + Luan.type(obj) + " as a boolean" ); - } - - public String toString(Object obj) throws LuanException { - LuanFunction fn = getHandlerFunction("__tostring",obj); - if( fn != null ) - return checkString( Luan.first( call(fn,"__tostring",new Object[]{obj}) ) ); - return Luan.toString(obj); - } - - public String repr(Object obj) throws LuanException { - LuanFunction fn = getHandlerFunction("__repr",obj); - if( fn != null ) - return checkString( Luan.first( call(fn,"__repr",new Object[]{obj}) ) ); - String repr = Luan.repr(obj); - if( repr==null ) - throw exception( "value '" + obj + "' doesn't support repr()" ); - return repr; - } - - public LuanFunction getHandlerFunction(String op,Object obj) throws LuanException { - Object f = luan.getHandler(op,obj); - if( f == null ) - return null; - return checkFunction(f); - } - - public LuanFunction getBinHandler(String op,Object o1,Object o2) throws LuanException { - LuanFunction f1 = getHandlerFunction(op,o1); - if( f1 != null ) - return f1; - return getHandlerFunction(op,o2); - } - - public boolean isLessThan(Object o1,Object o2) throws LuanException { - if( o1 instanceof Number && o2 instanceof Number ) { - Number n1 = (Number)o1; - Number n2 = (Number)o2; - return n1.doubleValue() < n2.doubleValue(); - } - if( o1 instanceof String && o2 instanceof String ) { - String s1 = (String)o1; - String s2 = (String)o2; - return s1.compareTo(s2) < 0; - } - LuanFunction fn = getBinHandler("__lt",o1,o2); - if( fn != null ) - return Luan.toBoolean( Luan.first(call(fn,"__lt",new Object[]{o1,o2})) ); - throw exception( "attempt to compare " + Luan.type(o1) + " with " + Luan.type(o2) ); - } - - public Object arithmetic(String op,Object o1,Object o2) throws LuanException { - LuanFunction fn = getBinHandler(op,o1,o2); - if( fn != null ) - return Luan.first(call(fn,op,new Object[]{o1,o2})); - String type = Luan.toNumber(o1)==null ? Luan.type(o1) : Luan.type(o2); - throw exception("attempt to perform arithmetic on a "+type+" value"); - } - -}
--- a/src/luan/LuanElement.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -package luan; - - -public abstract class LuanElement { - - final String toString(String fnName) { - String s = location(); - if( fnName != null ) - s += ": in function '" + fnName + "'"; - return s; - } - - abstract String location(); - - public static final LuanElement JAVA = new LuanElement(){ - @Override String location() { - return "Java"; - } - }; -}
--- a/src/luan/LuanException.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -package luan; - - -public class LuanException extends Exception { - private final String stackTrace; - - LuanException(LuanBit bit,Object msg) { - super(message(msg),cause(msg)); - stackTrace = stackTrace(bit,msg); - } - - @Override public String getMessage() { - return super.getMessage() + stackTrace; - } - - private String message() { - return super.getMessage(); - } - - private static Throwable cause(Object msg) { - return msg instanceof Throwable ? (Throwable)msg : null; - } - - private static String message(Object msg) { - if( msg instanceof LuanException ) { - LuanException le = (LuanException)msg; - return le.message(); -/* - } else if( msg instanceof Throwable ) { - Throwable t = (Throwable)msg; - return t.getMessage(); -*/ - } else { - return msg.toString(); - } - } - - private static String stackTrace(LuanBit bit,Object msg) { - StringBuilder buf = new StringBuilder(); - buf.append( bit.stackTrace() ); - if( msg instanceof LuanException ) { - LuanException le = (LuanException)msg; - buf.append( "\ncaused by:" ).append( le.stackTrace ); - } - return buf.toString(); - } -}
--- a/src/luan/LuanExitException.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -package luan; - - -public final class LuanExitException extends RuntimeException {}
--- a/src/luan/LuanFunction.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -package luan; - - -public abstract class LuanFunction implements LuanRepr { - - public abstract Object call(LuanState luan,Object[] args) throws LuanException; - - public static final Object[] NOTHING = new Object[0]; - - @Override public String toString() { - return "function: " + Integer.toHexString(hashCode()); - } - - @Override public String repr() { - return "<function>"; - } - -}
--- a/src/luan/LuanJavaFunction.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,516 +0,0 @@ -package luan; - -import java.lang.reflect.Array; -import java.lang.reflect.Method; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.Set; -import java.util.Arrays; - - -public final class LuanJavaFunction extends LuanFunction { - private final JavaMethod method; - private final Object obj; - private final RtnConverter rtnConverter; - private final boolean takesLuaState; - private final ArgConverter[] argConverters; - private final Class<?> varArgCls; - - public LuanJavaFunction(Method method,Object obj) { - this( JavaMethod.of(method), obj ); - } - - public LuanJavaFunction(Constructor constr,Object obj) { - this( JavaMethod.of(constr), obj ); - } - - LuanJavaFunction(JavaMethod method,Object obj) { - this.method = method; - this.obj = obj; - this.rtnConverter = getRtnConverter(method); - this.takesLuaState = takesLuaState(method); - this.argConverters = getArgConverters(takesLuaState,method); - if( method.isVarArgs() ) { - Class<?>[] paramTypes = method.getParameterTypes(); - this.varArgCls = paramTypes[paramTypes.length-1].getComponentType(); - } else { - this.varArgCls = null; - } - } - - @Override public String toString() { - return "java-function: " + method; - } - - public Class<?>[] getParameterTypes() { - return method.getParameterTypes(); - } - - @Override public Object call(LuanState luan,Object[] args) throws LuanException { - args = fixArgs(luan,args); - try { - return doCall(luan,args); - } catch(IllegalArgumentException e) { - checkArgs(luan,args); - throw e; - } - } - - public Object rawCall(LuanState luan,Object[] args) throws LuanException { - args = fixArgs(luan,args); - return doCall(luan,args); - } - - private Object doCall(LuanState luan,Object[] args) throws LuanException { - Object rtn; - try { - rtn = method.invoke(obj,args); - } catch(IllegalAccessException e) { - throw new RuntimeException("method = "+method,e); - } catch(InvocationTargetException e) { - Throwable cause = e.getCause(); - if( cause instanceof Error ) - throw (Error)cause; - if( cause instanceof LuanException ) - throw (LuanException)cause; - throw luan.exception(cause); - } catch(InstantiationException e) { - throw new RuntimeException(e); - } - return rtnConverter.convert(rtn); - } - - private static final Map<Class,Class> primitiveMap = new HashMap<Class,Class>(); - static { - primitiveMap.put(Boolean.TYPE,Boolean.class); - primitiveMap.put(Character.TYPE,Character.class); - primitiveMap.put(Byte.TYPE,Byte.class); - primitiveMap.put(Short.TYPE,Short.class); - primitiveMap.put(Integer.TYPE,Integer.class); - primitiveMap.put(Long.TYPE,Long.class); - primitiveMap.put(Float.TYPE,Float.class); - primitiveMap.put(Double.TYPE,Double.class); - primitiveMap.put(Void.TYPE,Void.class); - } - - private void checkArgs(LuanState luan,Object[] args) throws LuanException { - Class<?>[] a = getParameterTypes(); - int start = takesLuaState ? 1 : 0; - for( int i=start; i<a.length; i++ ) { - Class<?> paramType = a[i]; - Class<?> type = paramType; - if( type.isPrimitive() ) - type = primitiveMap.get(type); - Object arg = args[i]; - if( !type.isInstance(arg) ) { - String expected = paramType.getSimpleName(); - if( arg==null ) { - if( paramType.isPrimitive() ) - throw luan.exception("bad argument #"+(i+1-start)+" ("+expected+" expected, got nil)"); - } else { - String got = arg.getClass().getSimpleName(); - throw luan.exception("bad argument #"+(i+1-start)+" ("+expected+" expected, got "+got+")"); - } - } - } - } - - private Object[] fixArgs(LuanState luan,Object[] args) { - int n = argConverters.length; - Object[] rtn; - int start = 0; - if( !takesLuaState && varArgCls==null && args.length == n ) { - rtn = args; - } else { - if( takesLuaState ) - n++; - rtn = new Object[n]; - if( takesLuaState ) { - rtn[start++] = luan; - } - n = argConverters.length; - if( varArgCls != null ) { - n--; - if( args.length < argConverters.length ) { - rtn[rtn.length-1] = Array.newInstance(varArgCls,0); - } else { - int len = args.length - n; - Object varArgs = Array.newInstance(varArgCls,len); - ArgConverter ac = argConverters[n]; - for( int i=0; i<len; i++ ) { - Array.set( varArgs, i, ac.convert(args[n+i]) ); - } - rtn[rtn.length-1] = varArgs; - } - } - System.arraycopy(args,0,rtn,start,Math.min(args.length,n)); - } - for( int i=0; i<n; i++ ) { - rtn[start+i] = argConverters[i].convert(rtn[start+i]); - } - return rtn; - } - - - private interface RtnConverter { - public Object convert(Object obj); - } - - private static final RtnConverter RTN_NOTHING = new RtnConverter() { - @Override public Object[] convert(Object obj) { - return NOTHING; - } - }; - - private static final RtnConverter RTN_SAME = new RtnConverter() { - @Override public Object convert(Object obj) { - return obj; - } - }; - - private static RtnConverter getRtnConverter(JavaMethod m) { - Class<?> rtnType = m.getReturnType(); - if( rtnType == Void.TYPE ) - return RTN_NOTHING; - return RTN_SAME; - } - - private static boolean isNumber(Class<?> rtnType) { - return rtnType == Short.TYPE - || rtnType == Integer.TYPE - || rtnType == Long.TYPE - || rtnType == Float.TYPE - || rtnType == Double.TYPE - ; - } - - private interface ArgConverter { - public Object convert(Object obj); - } - - private static final ArgConverter ARG_SAME = new ArgConverter() { - public Object convert(Object obj) { - return obj; - } - }; - - private static final ArgConverter ARG_BOOLEAN = new ArgConverter() { - public Object convert(Object obj) { - return Luan.toBoolean(obj); - } - }; - - private static final ArgConverter ARG_BOOLEAN_OBJ = new ArgConverter() { - public Object convert(Object obj) { - return obj==null ? null : Luan.toBoolean(obj); - } - }; - - private static final ArgConverter ARG_DOUBLE = new ArgConverter() { - public Object convert(Object obj) { - if( obj instanceof Double ) - return obj; - if( obj instanceof Number ) { - Number n = (Number)obj; - return n.doubleValue(); - } - if( obj instanceof String ) { - String s = (String)obj; - try { - return Double.valueOf(s); - } catch(NumberFormatException e) {} - } - return obj; - } - }; - - private static final ArgConverter ARG_FLOAT = new ArgConverter() { - public Object convert(Object obj) { - if( obj instanceof Float ) - return obj; - if( obj instanceof Number ) { - Number n = (Number)obj; - return n.floatValue(); - } - if( obj instanceof String ) { - String s = (String)obj; - try { - return Float.valueOf(s); - } catch(NumberFormatException e) {} - } - return obj; - } - }; - - private static final ArgConverter ARG_LONG = new ArgConverter() { - public Object convert(Object obj) { - if( obj instanceof Long ) - return obj; - if( obj instanceof Number ) { - Number n = (Number)obj; - long r = n.longValue(); - if( r==n.doubleValue() ) - return r; - } - else if( obj instanceof String ) { - String s = (String)obj; - try { - return Long.valueOf(s); - } catch(NumberFormatException e) {} - } - return obj; - } - }; - - private static final ArgConverter ARG_INTEGER = new ArgConverter() { - public Object convert(Object obj) { - if( obj instanceof Integer ) - return obj; - if( obj instanceof Number ) { - Number n = (Number)obj; - int r = n.intValue(); - if( r==n.doubleValue() ) - return r; - } - else if( obj instanceof String ) { - String s = (String)obj; - try { - return Integer.valueOf(s); - } catch(NumberFormatException e) {} - } - return obj; - } - }; - - private static final ArgConverter ARG_SHORT = new ArgConverter() { - public Object convert(Object obj) { - if( obj instanceof Short ) - return obj; - if( obj instanceof Number ) { - Number n = (Number)obj; - short r = n.shortValue(); - if( r==n.doubleValue() ) - return r; - } - else if( obj instanceof String ) { - String s = (String)obj; - try { - return Short.valueOf(s); - } catch(NumberFormatException e) {} - } - return obj; - } - }; - - private static final ArgConverter ARG_BYTE = new ArgConverter() { - public Object convert(Object obj) { - if( obj instanceof Byte ) - return obj; - if( obj instanceof Number ) { - Number n = (Number)obj; - byte r = n.byteValue(); - if( r==n.doubleValue() ) - return r; - } - else if( obj instanceof String ) { - String s = (String)obj; - try { - return Byte.valueOf(s); - } catch(NumberFormatException e) {} - } - return obj; - } - }; - - private static final ArgConverter ARG_TABLE = new ArgConverter() { - public Object convert(Object obj) { - if( obj == null ) - return null; - if( obj instanceof List ) { - @SuppressWarnings("unchecked") - List<Object> list = (List<Object>)obj; - return new LuanTable(list); - } - if( obj instanceof Map ) { - @SuppressWarnings("unchecked") - Map<Object,Object> map = (Map<Object,Object>)obj; - return new LuanTable(map); - } - if( obj instanceof Set ) { - @SuppressWarnings("unchecked") - Set<Object> set = (Set<Object>)obj; - return new LuanTable(set); - } - Class cls = obj.getClass(); - if( cls.isArray() && !cls.getComponentType().isPrimitive() ) { - Object[] a = (Object[])obj; - return new LuanTable(Arrays.asList(a)); - } - return obj; - } - }; - - private static final ArgConverter ARG_MAP = new ArgConverter() { - public Object convert(Object obj) { - if( obj instanceof LuanTable ) { - LuanTable t = (LuanTable)obj; - return t.asMap(); - } - return obj; - } - }; - - private static final ArgConverter ARG_LIST = new ArgConverter() { - public Object convert(Object obj) { - if( obj instanceof LuanTable ) { - LuanTable t = (LuanTable)obj; - if( t.isList() ) - return t.asList(); - } - return obj; - } - }; - - private static final ArgConverter ARG_SET = new ArgConverter() { - public Object convert(Object obj) { - if( obj instanceof LuanTable ) { - LuanTable t = (LuanTable)obj; - if( t.isSet() ) - return t.asSet(); - } - return obj; - } - }; - - private static class ArgArray implements ArgConverter { - private final Object[] a; - - ArgArray(Class cls) { - a = (Object[])Array.newInstance(cls.getComponentType(),0); - } - - public Object convert(Object obj) { - if( obj instanceof LuanTable ) { - LuanTable t = (LuanTable)obj; - if( t.isList() ) { - try { - return t.asList().toArray(a); - } catch(ArrayStoreException e) {} - } - } - return obj; - } - } - - private static boolean takesLuaState(JavaMethod m) { - Class<?>[] paramTypes = m.getParameterTypes(); - return paramTypes.length > 0 && paramTypes[0].equals(LuanState.class); - } - - private static ArgConverter[] getArgConverters(boolean takesLuaState,JavaMethod m) { - final boolean isVarArgs = m.isVarArgs(); - Class<?>[] paramTypes = m.getParameterTypes(); - if( takesLuaState ) { - Class<?>[] t = new Class<?>[paramTypes.length-1]; - System.arraycopy(paramTypes,1,t,0,t.length); - paramTypes = t; - } - ArgConverter[] a = new ArgConverter[paramTypes.length]; - for( int i=0; i<a.length; i++ ) { - Class<?> paramType = paramTypes[i]; - if( isVarArgs && i == a.length-1 ) - paramType = paramType.getComponentType(); - a[i] = getArgConverter(paramType); - } - return a; - } - - private static ArgConverter getArgConverter(Class<?> cls) { - if( cls == Boolean.TYPE ) - return ARG_BOOLEAN; - if( cls.equals(Boolean.class) ) - return ARG_BOOLEAN_OBJ; - if( cls == Double.TYPE || cls.equals(Double.class) ) - return ARG_DOUBLE; - if( cls == Float.TYPE || cls.equals(Float.class) ) - return ARG_FLOAT; - if( cls == Long.TYPE || cls.equals(Long.class) ) - return ARG_LONG; - if( cls == Integer.TYPE || cls.equals(Integer.class) ) - 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; - if( cls.equals(LuanTable.class) ) - return ARG_TABLE; - if( cls.equals(Map.class) ) - return ARG_MAP; - if( cls.equals(List.class) ) - return ARG_LIST; - if( cls.equals(Set.class) ) - return ARG_SET; - if( cls.isArray() && !cls.getComponentType().isPrimitive() ) - return new ArgArray(cls); - return ARG_SAME; - } - - - - private static abstract class JavaMethod { - abstract boolean isVarArgs(); - abstract Class<?>[] getParameterTypes(); - abstract Object invoke(Object obj,Object... args) - throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException; - abstract Class<?> getReturnType(); - - static JavaMethod of(final Method m) { - return new JavaMethod() { - @Override boolean isVarArgs() { - return m.isVarArgs(); - } - @Override Class<?>[] getParameterTypes() { - return m.getParameterTypes(); - } - @Override Object invoke(Object obj,Object... args) - throws IllegalAccessException, IllegalArgumentException, InvocationTargetException - { - return m.invoke(obj,args); - } - @Override Class<?> getReturnType() { - return m.getReturnType(); - } - @Override public String toString() { - return m.toString(); - } - }; - } - - static JavaMethod of(final Constructor c) { - return new JavaMethod() { - @Override boolean isVarArgs() { - return c.isVarArgs(); - } - @Override Class<?>[] getParameterTypes() { - return c.getParameterTypes(); - } - @Override Object invoke(Object obj,Object... args) - throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException - { - return c.newInstance(args); - } - @Override Class<?> getReturnType() { - return c.getDeclaringClass(); - } - @Override public String toString() { - return c.toString(); - } - }; - } - - } - -}
--- a/src/luan/LuanRepr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -package luan; - - -public interface LuanRepr { - public String repr(); -}
--- a/src/luan/LuanRuntimeException.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -package luan; - - -public final class LuanRuntimeException extends RuntimeException { - public LuanRuntimeException(LuanException e) { - super(e); - } -}
--- a/src/luan/LuanSource.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -package luan; - - -public final class LuanSource { - public final String name; - public final String text; - - public LuanSource(String name,String text) { - this.name = name; - this.text = text; - } - - public static final class CompilerElement extends LuanElement { - public final LuanSource source; - - public CompilerElement(LuanSource source) { - if( source==null ) - throw new NullPointerException("source is null"); - this.source = source; - } - - @Override String location() { - return "Compiling " + source.name; - } - } - - public static final class Element extends LuanElement { - public final LuanSource source; - public final int start; - public final int end; - - public Element(LuanSource source,int start,int end) { - if( source==null ) - throw new NullPointerException("source is null"); - this.source = source; - this.start = start; - while( end > 0 && Character.isWhitespace(source.text.charAt(end-1)) ) { - end--; - } - this.end = end; - } - - public String text() { - return source.text.substring(start,end); - } - - @Override String location() { - return source.name + ':' + lineNumber(); - } - - private int lineNumber() { - int line = 0; - int i = -1; - do { - line++; - i = source.text.indexOf('\n',i+1); - } while( i != -1 && i < start ); - return line; - } - - } -}
--- a/src/luan/LuanState.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,181 +0,0 @@ -package luan; - -import java.io.InputStream; -import java.io.PrintStream; -import java.util.List; -import java.util.ArrayList; -import java.util.Map; -import java.util.LinkedHashMap; -import luan.impl.LuanCompiler; -import luan.modules.BasicLuan; -import luan.modules.PackageLuan; - - -public abstract class LuanState implements DeepCloneable<LuanState> { - private final LuanBit JAVA = bit(LuanElement.JAVA); - - public LuanException exception(Object msg) { - return JAVA.exception(msg); - } - - public Object call(LuanFunction fn) throws LuanException { - return call(fn,null,LuanFunction.NOTHING); - } - - public Object call(LuanFunction fn,String fnName) throws LuanException { - return call(fn,fnName,LuanFunction.NOTHING); - } - - public Object call(LuanFunction fn,Object[] args) throws LuanException { - return call(fn,null,args); - } - - public Object call(LuanFunction fn,String fnName,Object[] args) throws LuanException { - return JAVA.call(fn,fnName,args); - } - - public LuanFunction checkFunction(Object obj) throws LuanException { - return JAVA.checkFunction(obj); - } - - public String toString(Object obj) throws LuanException { - return JAVA.toString(obj); - } - - public String repr(Object obj) throws LuanException { - return JAVA.repr(obj); - } - - public boolean isLessThan(Object o1,Object o2) throws LuanException { - return JAVA.isLessThan(o1,o2); - } - - - - private LuanTable global; - private LuanTable loaded; - private LuanTable preload; - private LuanTable searchers; - - private final List<MetatableGetter> mtGetters; - final List<StackTraceElement> stackTrace = new ArrayList<StackTraceElement>(); - - protected LuanState() { - global = new LuanTable(); - global.put("_G",global); - global.put( "_VERSION", Luan.version ); - loaded = new LuanTable(); - preload = new LuanTable(); - searchers = new LuanTable(); - mtGetters = new ArrayList<MetatableGetter>(); - } - - protected LuanState(LuanState luan) { - mtGetters = new ArrayList<MetatableGetter>(luan.mtGetters); - } - - @Override public void deepenClone(LuanState clone,DeepCloner cloner) { - clone.global = cloner.deepClone(global); - clone.loaded = cloner.deepClone(loaded); - clone.preload = cloner.deepClone(preload); - clone.searchers = cloner.deepClone(searchers); - } - - public abstract LuanTable currentEnvironment(); - - public final LuanTable global() { - return global; - } - - public final LuanTable loaded() { - return loaded; - } - - public final LuanTable preload() { - return preload; - } - - public final LuanTable searchers() { - return searchers; - } - - public final Object get(String name) { - String[] a = name.split("\\."); - LuanTable t = loaded; - for( int i=0; i<a.length-1; i++ ) { - Object obj = t.get(a[i]); - if( !(obj instanceof LuanTable) ) - return null; - t = (LuanTable)obj; - } - return t.get(a[a.length-1]); - } - - public final Object set(String name,Object value) { - String[] a = name.split("\\."); - LuanTable t = loaded; - for( int i=0; i<a.length-1; i++ ) { - Object obj = t.get(a[i]); - if( !(obj instanceof LuanTable) ) - return null; - t = (LuanTable)obj; - } - return t.put(a[a.length-1],value); - } - - public final void globalImport(String modName) throws LuanException { - Object mod = PackageLuan.require(this,modName); - global.put(modName,mod); - } - - public static LuanState newStandard() { - try { - LuanState luan = LuanCompiler.newLuanState(); - luan.globalImport("Package"); - BasicLuan.do_file(luan,"java:luan/init.luan"); - return luan; - } catch(LuanException e) { - throw new RuntimeException(e); - } - } - - public final Object eval(String cmd) { - return eval(cmd,new LuanTable()); - } - - public final Object eval(String cmd,LuanTable env) { - try { - LuanFunction fn = BasicLuan.load(this,cmd,"eval",env,true); - return call(fn); - } catch(LuanException e) { - throw new RuntimeException(e); - } - } - - public final LuanTable getMetatable(Object obj) { - if( obj instanceof LuanTable ) { - LuanTable table = (LuanTable)obj; - return table.getMetatable(); - } - for( MetatableGetter mg : mtGetters ) { - LuanTable table = mg.getMetatable(obj); - if( table != null ) - return table; - } - return null; - } - - public final void addMetatableGetter(MetatableGetter mg) { - mtGetters.add(mg); - } - - public final LuanBit bit(LuanElement el) { - return new LuanBit(this,el); - } - - public final Object getHandler(String op,Object obj) { - LuanTable t = getMetatable(obj); - return t==null ? null : t.get(op); - } - -}
--- a/src/luan/LuanTable.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,388 +0,0 @@ -package luan; - -import java.util.Iterator; -import java.util.ListIterator; -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Set; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.regex.Pattern; - - -public final class LuanTable implements DeepCloneable<LuanTable>, Iterable<Map.Entry<Object,Object>>, LuanRepr { - private Map<Object,Object> map = null; - private List<Object> list = null; - private LuanTable metatable = null; - - public LuanTable() {} - - public LuanTable(LuanTable tbl) { - if( tbl.map != null ) - this.map = new HashMap<Object,Object>(tbl.map); - if( tbl.list != null ) - this.list = new ArrayList<Object>(tbl.list); - } - - public LuanTable(List<Object> list) { - this.list = list; - this.map = new HashMap<Object,Object>(); - map.put("n",list.size()); - for( int i=0; i<list.size(); i++ ) { - if( list.get(i) == null ) { - listToMap(i); - break; - } - } - } - - public LuanTable(Map<Object,Object> map) { - map.remove(null); - for( Iterator<Object> i=map.values().iterator(); i.hasNext(); ) { - if( i.next() == null ) - i.remove(); - } - this.map = map; - } - - public LuanTable(Set<Object> set) { - map = new HashMap<Object,Object>(); - for( Object obj : set ) { - if( obj != null ) - map.put(obj,Boolean.TRUE); - } - } - - @Override public LuanTable shallowClone() { - return new LuanTable(); - } - - @Override public void deepenClone(LuanTable clone,DeepCloner cloner) { - if( map != null ) { - clone.map = new HashMap<Object,Object>(); - for( Map.Entry<Object,Object> entry : map.entrySet() ) { - clone.map.put( cloner.get(entry.getKey()), cloner.get(entry.getValue()) ); - } - } - if( list != null ) { - clone.list = new ArrayList<Object>(); - for( Object obj : list ) { - clone.list.add( cloner.get(obj) ); - } - } - if( metatable != null ) - clone.metatable = cloner.deepClone(metatable); - } - - public boolean isList() { - return map==null || map.isEmpty(); - } - - public List<Object> asList() { - return list!=null ? list : Collections.emptyList(); - } - - public Map<Object,Object> asMap() { - if( list == null || list.isEmpty() ) - return map!=null ? map : Collections.emptyMap(); - Map<Object,Object> rtn = map!=null ? new HashMap<Object,Object>(map) : new HashMap<Object,Object>(); - for( ListIterator iter = list.listIterator(); iter.hasNext(); ) { - int i = iter.nextIndex(); - rtn.put(i+1,iter.next()); - } - return rtn; - } - - public boolean isSet() { - if( list != null ) { - for( Object obj : list ) { - if( obj!=null && !obj.equals(Boolean.TRUE) ) - return false; - } - } - if( map != null ) { - for( Object obj : map.values() ) { - if( !obj.equals(Boolean.TRUE) ) - return false; - } - } - return true; - } - - public Set<Object> asSet() { - if( list == null || list.isEmpty() ) - return map!=null ? map.keySet() : Collections.emptySet(); - Set<Object> rtn = map!=null ? new HashSet<Object>(map.keySet()) : new HashSet<Object>(); - for( int i=1; i<=list.size(); i++ ) { - rtn.add(i); - } - return rtn; - } - - @Override public String toString() { - return "table: " + Integer.toHexString(hashCode()); - } - - @Override public String repr() { - return repr( Collections.newSetFromMap(new IdentityHashMap<LuanTable,Boolean>()) ); - } - - private String repr(Set<LuanTable> set) { - if( !set.add(this) ) { - return "\"<circular reference>\""; - } - StringBuilder sb = new StringBuilder(); - sb.append('{'); - boolean isFirst = true; - if( list != null ) { - boolean gotNull = false; - for( int i=0; i<list.size(); i++ ) { - Object obj = list.get(i); - if( obj==null ) { - gotNull = true; - } else { - if( isFirst ) { - isFirst = false; - } else { - sb.append(", "); - } - if( gotNull ) - sb.append(i+1).append('='); - sb.append(repr(set,obj)); - } - } - } - if( map != null ) { - for( Map.Entry<Object,Object> entry : map.entrySet() ) { - if( isFirst ) { - isFirst = false; - } else { - sb.append(", "); - } - sb.append(reprKey(set,entry.getKey())).append('=').append(repr(set,entry.getValue())); - } - } - sb.append('}'); - return sb.toString(); - } - - private static final Pattern namePtn = Pattern.compile("[a-zA-Z_][a-zA-Z_0-9]*"); - - private static String reprKey(Set<LuanTable> set,Object obj) { - if( obj instanceof String ) { - String s = (String)obj; - if( namePtn.matcher(s).matches() ) - return s; - } - return "[" + repr(set,obj) + "]"; - } - - private static String repr(Set<LuanTable> set,Object obj) { - if( obj instanceof LuanTable ) { - LuanTable t = (LuanTable)obj; - return t.repr(set); - } else { - String s = Luan.repr(obj); - if( s == null ) - s = "<couldn't repr: " + Luan.stringEncode(Luan.toString(obj)) + ">"; - return s; - } - } - - public Object get(Object key) { - if( list != null ) { - Integer iT = Luan.asInteger(key); - if( iT != null ) { - int i = iT - 1; - if( i>=0 && i<list.size() ) - return list.get(i); - } - } - if( map==null ) - return null; - return map.get(key); - } - - public Object put(Object key,Object val) { - Integer iT = Luan.asInteger(key); - if( iT != null ) { - int i = iT - 1; - if( list != null || i == 0 ) { - if( i == list().size() ) { - if( val != null ) { - list.add(val); - mapToList(); - } - return null; - } else if( i>=0 && i<list.size() ) { - Object old = list.get(i); - list.set(i,val); - if( val == null ) { - listToMap(i); - } - return old; - } - } - } - if( map==null ) { - map = new HashMap<Object,Object>(); - } - if( key instanceof Number && !(key instanceof Double) ) { - Number n = (Number)key; - key = Double.valueOf(n.doubleValue()); - } - if( val == null ) { - return map.remove(key); - } else { - return map.put(key,val); - } - } - - private void mapToList() { - if( map != null ) { - while(true) { - Object v = map.remove(Double.valueOf(list.size()+1)); - if( v == null ) - break; - list.add(v); - } - } - } - - private void listToMap(int from) { - if( list != null ) { - while( list.size() > from ) { - int i = list.size() - 1; - Object v = list.remove(i); - if( v != null ) { - if( map==null ) - map = new HashMap<Object,Object>(); - map.put(i+1,v); - } - } - } - } - - private List<Object> list() { - if( list == null ) { - list = new ArrayList<Object>(); - mapToList(); - } - return list; - } - - public void insert(int pos,Object value) { - if( value==null ) - throw new UnsupportedOperationException(); - list().add(pos-1,value); - mapToList(); - } - - public void add(Object value) { - if( value==null ) - throw new UnsupportedOperationException(); - list().add(value); - mapToList(); - } - - public Object remove(int pos) { - return list().remove(pos-1); - } - - public void sort(Comparator<Object> cmp) { - Collections.sort(list(),cmp); - } - - public int length() { - return list==null ? 0 : list.size(); - } - - public Iterator<Map.Entry<Object,Object>> iterator() { - if( list == null ) { - if( map == null ) - return Collections.<Map.Entry<Object,Object>>emptyList().iterator(); - return map.entrySet().iterator(); - } - if( map == null ) - return listIterator(); - return new Iterator<Map.Entry<Object,Object>>() { - Iterator<Map.Entry<Object,Object>> iter = listIterator(); - boolean isList = true; - public boolean hasNext() { - boolean b = iter.hasNext(); - if( !b && isList ) { - iter = map.entrySet().iterator(); - isList = false; - b = iter.hasNext(); - } - return b; - } - public Map.Entry<Object,Object> next() { - return iter.next(); - } - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - - public Iterator<Map.Entry<Object,Object>> listIterator() { - if( list == null ) - return Collections.<Map.Entry<Object,Object>>emptyList().iterator(); - final ListIterator iter = list.listIterator(); - return new Iterator<Map.Entry<Object,Object>>() { - public boolean hasNext() { - return iter.hasNext(); - } - public Map.Entry<Object,Object> next() { - Double key = Double.valueOf(iter.nextIndex()+1); - return new MapEntry(key,iter.next()); - } - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } -/* - public Object[] listToArray() { - return list==null ? new Object[0] : list.toArray(); - } -*/ - public LuanTable subList(int from,int to) { - return new LuanTable(new ArrayList<Object>(list().subList(from-1,to-1))); - } - - public LuanTable getMetatable() { - return metatable; - } - - public void setMetatable(LuanTable metatable) { - this.metatable = metatable; - } - - private static final class MapEntry implements Map.Entry<Object,Object> { - private final Object key; - private final Object value; - - MapEntry(Object key,Object value) { - this.key = key; - this.value = value; - } - - @Override public Object getKey() { - return key; - } - - @Override public Object getValue() { - return value; - } - - @Override public Object setValue(Object value) { - throw new UnsupportedOperationException(); - } - } -}
--- a/src/luan/MetatableGetter.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -package luan; - -public interface MetatableGetter { - public LuanTable getMetatable(Object obj); -}
--- a/src/luan/StackTraceElement.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -package luan; - - -final class StackTraceElement { - final LuanElement call; - final String fnName; - - StackTraceElement(LuanElement call,String fnName) { - this.call = call; - this.fnName = fnName; - } -}
--- a/src/luan/cmd_line.luan Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ - -local standalone_usage = [=[ -usage: java luan.CmdLine [options] [script [args]] -Available options are: - -e stat execute string 'stat' - -i enter interactive mode after executing 'script' - -v show version information - -- stop handling options - - stop handling options and execute stdin -]=] - -local function standalone_error(msg) - Io.stderr.write( msg, "\n", standalone_usage ) -end - - -local args = {...} -local interactive = false -local showVersion = false -local i = 1 -if #args == 0 then - interactive = true - showVersion = true -else - while i <= #args do - local arg = args[i] - if arg.sub(1,1) ~= "-" or arg == "--" then - break - end - if arg == "-i" then - interactive = true - elseif arg == "-v" then - showVersion = true - elseif arg == "-e" then - i = i + 1 - if i == #args then - standalone_error "'-e' needs argument" - return - end - local cmd = args[i] - local stat = load(cmd,"(command line)",true,true) - local result = Table.pack( stat() ) - if result.n > 0 then - print( Table.unpack(result,1,result.n) ) - end - elseif arg == "-" then - local src = Io.stdin.read_text() - local stdin = load(src,"stdin") - stdin() - return - else - standalone_error( "unrecognized option '"..arg.."'" ) - return - end - i = i + 1 - end -end -if showVersion then print(_VERSION) end -if i <= #args then - local file = args[i] - _G.arg = {} - for j,v in ipairs(args) do - _G.arg[j-i] = v - end - local main_file = load_file(file) - main_file( Table.unpack(_G.arg) ) -end -if interactive then - Debug.debug("> ") -end
--- a/src/luan/impl/AddExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class AddExpr extends BinaryOpExpr { - - AddExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object o1 = op1.eval(luan); - Object o2 = op2.eval(luan); - Number n1 = Luan.toNumber(o1); - Number n2 = Luan.toNumber(o2); - if( n1 != null && n2 != null ) - return n1.doubleValue() + n2.doubleValue(); - return arithmetic(luan,"__add",o1,o2); - } -}
--- a/src/luan/impl/AndExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class AndExpr extends BinaryOpExpr { - - AndExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object v1 = op1.eval(luan); - return !Luan.toBoolean(v1) ? v1 : op2.eval(luan); - } -}
--- a/src/luan/impl/BinaryOpExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanException; -import luan.LuanSource; - - -abstract class BinaryOpExpr extends CodeImpl implements Expr { - final Expr op1; - final Expr op2; - - BinaryOpExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se); - this.op1 = op1; - this.op2 = op2; - } - - Object arithmetic(LuanStateImpl luan,String op,Object o1,Object o2) throws LuanException { - return luan.bit(se()).arithmetic("__mod",o1,o2); - } - -}
--- a/src/luan/impl/Block.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -package luan.impl; - -import luan.LuanException; - - -final class Block implements Stmt { - final Stmt[] stmts; - private final int stackStart; - private final int stackEnd; - - Block(Stmt[] stmts,int stackStart,int stackEnd) { - if( stmts.length==0 ) - throw new RuntimeException("empty block"); - this.stmts = stmts; - this.stackStart = stackStart; - this.stackEnd = stackEnd; - } - - @Override public void eval(LuanStateImpl luan) throws LuanException { - try { - for( Stmt stmt : stmts ) { - stmt.eval(luan); - } - } finally { - luan.stackClear(stackStart,stackEnd); - } - } - -}
--- a/src/luan/impl/BreakException.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -package luan.impl; - - -final class BreakException extends RuntimeException {}
--- a/src/luan/impl/BreakStmt.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -package luan.impl; - - -final class BreakStmt implements Stmt { - - @Override public void eval(LuanStateImpl luan) { - throw new BreakException(); - } -}
--- a/src/luan/impl/Closure.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanFunction; -import luan.LuanState; -import luan.LuanElement; -import luan.LuanException; -import luan.DeepCloner; -import luan.DeepCloneable; - - -final class Closure extends LuanFunction implements DeepCloneable<Closure> { - private final FnDef fnDef; - private UpValue[] upValues; - - Closure(LuanStateImpl luan,FnDef fnDef) throws LuanException { - this.fnDef = fnDef; - UpValue.Getter[] upValueGetters = fnDef.upValueGetters; - upValues = new UpValue[upValueGetters.length]; - for( int i=0; i<upValues.length; i++ ) { - upValues[i] = upValueGetters[i].get(luan); - } - } - - private Closure(Closure c) { - this.fnDef = c.fnDef; - } - - @Override public Closure shallowClone() { - return new Closure(this); - } - - @Override public void deepenClone(Closure clone,DeepCloner cloner) { - clone.upValues = cloner.deepClone(upValues); - } - - UpValue[] upValues() { - return upValues; - } - - @Override public Object call(LuanState luan,Object[] args) throws LuanException { - return call(this,(LuanStateImpl)luan,args); - } - - private static Object call(Closure closure,LuanStateImpl luan,Object[] args) throws LuanException { - while(true) { - FnDef fnDef = closure.fnDef; - Object[] varArgs = null; - if( fnDef.isVarArg ) { - if( args.length > fnDef.numArgs ) { - varArgs = new Object[ args.length - fnDef.numArgs ]; - for( int i=0; i<varArgs.length; i++ ) { - varArgs[i] = args[fnDef.numArgs+i]; - } - } else { - varArgs = LuanFunction.NOTHING; - } - } - Object[] stack = luan.newFrame(closure,fnDef.stackSize,varArgs); - final int n = Math.min(args.length,fnDef.numArgs); - for( int i=0; i<n; i++ ) { - stack[i] = args[i]; - } - Object returnValues; - try { - fnDef.block.eval(luan); - } catch(ReturnException e) { - } finally { - returnValues = luan.returnValues; - closure = luan.tailFn; - luan.popFrame(); - } - if( closure == null ) - return returnValues; - args = Luan.array(returnValues); - } - } - -}
--- a/src/luan/impl/Code.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -package luan.impl; - -import luan.LuanSource; - - -interface Code { - public LuanSource.Element se(); -}
--- a/src/luan/impl/CodeImpl.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -package luan.impl; - -import luan.LuanSource; - - -class CodeImpl implements Code { - final LuanSource.Element se; - - CodeImpl(LuanSource.Element se) { - this.se = se; - } - - @Override public final LuanSource.Element se() { - return se; - } -}
--- a/src/luan/impl/ConcatExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanFunction; -import luan.LuanException; -import luan.LuanSource; - - -final class ConcatExpr extends BinaryOpExpr { - - ConcatExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object o1 = op1.eval(luan); - Object o2 = op2.eval(luan); - String s1 = luan.bit(op1.se()).toString(o1); - String s2 = luan.bit(op2.se()).toString(o2); -/* - if( s1 != null && s2 != null ) - return s1 + s2; - LuanFunction fn = luan.getBinHandler(se,"__concat",o1,o2); - if( fn != null ) - return Luan.first(luan.call(fn,se,"__concat",o1,o2)); - String type = s1==null ? Luan.type(o1) : Luan.type(o2); - throw new LuanException( luan, se, "attempt to concatenate a " + type + " value" ); -*/ - return s1 + s2; - } -}
--- a/src/luan/impl/ConstExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -package luan.impl; - -import luan.LuanSource; - - -final class ConstExpr extends CodeImpl implements Expr { - private final Object obj; - - ConstExpr(Object obj) { - this(null,obj); - } - - ConstExpr(LuanSource.Element se,Object obj) { - super(se); - this.obj = obj; - } - - @Override public Object eval(LuanStateImpl luan) { - return obj; - } - - @Override public String toString() { - return "(ConstExpr "+obj+")"; - } -}
--- a/src/luan/impl/DivExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class DivExpr extends BinaryOpExpr { - - DivExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object o1 = op1.eval(luan); - Object o2 = op2.eval(luan); - Number n1 = Luan.toNumber(o1); - Number n2 = Luan.toNumber(o2); - if( n1 != null && n2 != null ) - return n1.doubleValue() / n2.doubleValue(); - return arithmetic(luan,"__div",o1,o2); - } -}
--- a/src/luan/impl/EqExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanFunction; -import luan.LuanTable; -import luan.LuanException; -import luan.LuanSource; -import luan.LuanBit; - - -final class EqExpr extends BinaryOpExpr { - - EqExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object o1 = op1.eval(luan); - Object o2 = op2.eval(luan); - if( o1 == o2 || o1 != null && o1.equals(o2) ) - return true; - if( o1 instanceof Number && o2 instanceof Number ) { - Number n1 = (Number)o1; - Number n2 = (Number)o2; - return n1.doubleValue() == n2.doubleValue(); - } - if( o1==null || o2==null || !o1.getClass().equals(o2.getClass()) ) - return false; - LuanTable mt1 = luan.getMetatable(o1); - LuanTable mt2 = luan.getMetatable(o2); - if( mt1==null || mt2==null ) - return false; - Object f = mt1.get("__eq"); - if( f == null || !f.equals(mt2.get("__eq")) ) - return null; - LuanBit bit = luan.bit(se); - LuanFunction fn = bit.checkFunction(f); - return Luan.toBoolean( Luan.first(bit.call(fn,"__eq",new Object[]{o1,o2})) ); - } -}
--- a/src/luan/impl/ExpList.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -package luan.impl; - -import java.util.List; -import java.util.ArrayList; -import java.util.Arrays; -import luan.LuanException; -import luan.LuanSource; -import luan.LuanFunction; -import luan.Luan; - - -final class ExpList { - - static final Expressions emptyExpList = new Expressions() { - - @Override public Object[] eval(LuanStateImpl luan) { - return LuanFunction.NOTHING; - } - - @Override public LuanSource.Element se() { - return null; - } - }; - - static Expr[] toArray(List<Expressions> list) { - Expr[] a = new Expr[list.size()]; - for( int i=0; i<a.length; i++ ) { - Expressions exprs = list.get(i); - if( exprs instanceof Expr ) { - a[i] = (Expr)exprs; - } else { - a[i] = new ExpressionsExpr(exprs); - } - } - return a; - } - - static Expressions build(List<Expressions> list) { - switch(list.size()) { - case 0: - return emptyExpList; - case 1: - return list.get(0); - default: - if( list.get(list.size()-1) instanceof Expr ) { - return new ExprList1( toArray(list) ); - } else { - Expressions last = list.remove(list.size()-1); - return new ExprList2( toArray(list), last ); - } - } - } - - private static class ExprList1 implements Expressions { - private final Expr[] exprs; - - private ExprList1(Expr[] exprs) { - this.exprs = exprs; - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object[] a = new Object[exprs.length]; - for( int i=0; i<exprs.length; i++ ) { - a[i] = exprs[i].eval(luan); - } - return a; - } - - @Override public LuanSource.Element se() { - return new LuanSource.Element(exprs[0].se().source,exprs[0].se().start,exprs[exprs.length-1].se().end); - } - } - - private static class ExprList2 implements Expressions { - private final Expr[] exprs; - private final Expressions last; - - private ExprList2(Expr[] exprs,Expressions last) { - this.exprs = exprs; - this.last = last; - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - List<Object> list = new ArrayList<Object>(); - for( Expr expr : exprs ) { - list.add( expr.eval(luan) ); - } - list.addAll( Arrays.asList(Luan.array( last.eval(luan) )) ); - return list.toArray(); - } - - @Override public LuanSource.Element se() { - return new LuanSource.Element(exprs[0].se().source,exprs[0].se().start,last.se().end); - } - } -}
--- a/src/luan/impl/Expr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -package luan.impl; - -import luan.LuanException; - - -interface Expr extends Expressions {}
--- a/src/luan/impl/Expressions.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -package luan.impl; - -import luan.LuanException; - - -interface Expressions extends Code { - public Object eval(LuanStateImpl luan) throws LuanException; -}
--- a/src/luan/impl/ExpressionsExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -package luan.impl; - -import java.util.List; -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class ExpressionsExpr implements Expr { - private final Expressions expressions; - - ExpressionsExpr(Expressions expressions) { - this.expressions = expressions; - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - return Luan.first( expressions.eval(luan) ); - } - - public LuanSource.Element se() { - return expressions.se(); - } - -}
--- a/src/luan/impl/ExpressionsStmt.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -package luan.impl; - -import luan.LuanException; - - -final class ExpressionsStmt implements Stmt { - private final Expressions expressions; - - ExpressionsStmt(Expressions expressions) { - this.expressions = expressions; - } - - @Override public void eval(LuanStateImpl luan) throws LuanException { - expressions.eval(luan); - } - -}
--- a/src/luan/impl/FnCall.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanFunction; -import luan.LuanException; -import luan.LuanSource; - - -final class FnCall extends CodeImpl implements Expressions { - final Expr fnExpr; - final Expressions args; - final String fnName; - - FnCall(LuanSource.Element se,Expr fnExpr,Expressions args) { - super(se); - this.fnExpr = fnExpr; - this.args = args; - this.fnName = fnExpr.se().text(); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - return call( luan, fnExpr.eval(luan) ); - } - - private Object call(LuanStateImpl luan,Object o) throws LuanException { - if( o instanceof LuanFunction ) { - LuanFunction fn = (LuanFunction)o; - return luan.bit(se).call( fn, fnName, Luan.array(args.eval(luan)) ); - } - Object h = luan.getHandler("__call",o); - if( h != null ) - return call(luan,h); - throw luan.bit(fnExpr.se()).exception( "attempt to call '"+fnExpr.se().text()+"' (a " + Luan.type(o) + " value)" ); - } - - @Override public String toString() { - return "(FnCall "+fnName+" "+fnExpr+" "+args+")"; - } -}
--- a/src/luan/impl/FnDef.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -package luan.impl; - -import luan.LuanException; -import luan.LuanSource; - - -final class FnDef extends CodeImpl implements Expr { - final Stmt block; - final int stackSize; - final int numArgs; - final boolean isVarArg; - final UpValue.Getter[] upValueGetters; - - FnDef(LuanSource.Element se,Stmt block,int stackSize,int numArgs,boolean isVarArg,UpValue.Getter[] upValueGetters) { - super(se); - this.block = block; - this.stackSize = stackSize; - this.numArgs = numArgs; - this.isVarArg = isVarArg; - this.upValueGetters = upValueGetters; - fixReturns(block); - } - - private static void fixReturns(Stmt stmt) { - if( stmt instanceof ReturnStmt ) { - ReturnStmt rs = (ReturnStmt)stmt; - rs.throwReturnException = false; - } else if( stmt instanceof Block ) { - Block b = (Block)stmt; - fixReturns( b.stmts[b.stmts.length-1] ); - } else if( stmt instanceof IfStmt ) { - IfStmt is = (IfStmt)stmt; - fixReturns( is.thenStmt ); - fixReturns( is.elseStmt ); - } - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - return new Closure(luan,this); - } - -}
--- a/src/luan/impl/ForStmt.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanFunction; -import luan.LuanSource; -import luan.LuanBit; - - -final class ForStmt extends CodeImpl implements Stmt { - private final int iVars; - private final int nVars; - private final Expr iterExpr; - private final Stmt block; - - ForStmt(LuanSource.Element se,int iVars,int nVars,Expr iterExpr,Stmt block) { - super(se); - this.iVars = iVars; - this.nVars = nVars; - this.iterExpr = iterExpr; - this.block = block; - } - - @Override public void eval(LuanStateImpl luan) throws LuanException { - LuanFunction iter = luan.bit(se).checkFunction( iterExpr.eval(luan) ); - LuanBit bit = luan.bit(iterExpr.se()); - String name = iterExpr.se().text(); - try { - while(true) { - Object vals = bit.call(iter,name,LuanFunction.NOTHING); - if( vals==null ) - break; - if( vals instanceof Object[] ) { - Object[] a = (Object[])vals; - if( a.length==0 ) - break; - for( int i=0; i<nVars; i++ ) { - luan.stackSet( iVars+i, i < a.length ? a[i] : null ); - } - } else { - luan.stackSet( iVars, vals ); - for( int i=1; i<nVars; i++ ) { - luan.stackSet( iVars+i, null ); - } - } - block.eval(luan); - } - } catch(BreakException e) { - } finally { - luan.stackClear(iVars,iVars+nVars); - } - } - -}
--- a/src/luan/impl/GetLocalVar.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -package luan.impl; - -import luan.LuanSource; - - -final class GetLocalVar extends CodeImpl implements Expr { - private final int index; - - GetLocalVar(LuanSource.Element se,int index) { - super(se); - this.index = index; - } - - @Override public Object eval(LuanStateImpl luan) { - return luan.stackGet(index); - } -}
--- a/src/luan/impl/GetUpVar.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -package luan.impl; - -import luan.LuanSource; - - -final class GetUpVar extends CodeImpl implements Expr { - private final int index; - - GetUpVar(LuanSource.Element se,int index) { - super(se); - this.index = index; - } - - @Override public Object eval(LuanStateImpl luan) { - return luan.closure().upValues()[index].get(); - } -}
--- a/src/luan/impl/IfStmt.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class IfStmt extends CodeImpl implements Stmt { - private final Expr cnd; - final Stmt thenStmt; - final Stmt elseStmt; - - IfStmt(LuanSource.Element se,Expr cnd,Stmt thenStmt,Stmt elseStmt) { - super(se); - this.cnd = cnd; - this.thenStmt = thenStmt; - this.elseStmt = elseStmt; - } - - @Override public void eval(LuanStateImpl luan) throws LuanException { - if( luan.bit(se).checkBoolean( cnd.eval(luan) ) ) { - thenStmt.eval(luan); - } else { - elseStmt.eval(luan); - } - } -}
--- a/src/luan/impl/IndexExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanSource; - - -final class IndexExpr extends BinaryOpExpr { - - IndexExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - return index(luan,op1.eval(luan),op2.eval(luan)); - } - - private Object index(LuanStateImpl luan,Object t,Object key) throws LuanException { - Object h; - if( t instanceof LuanTable ) { - LuanTable tbl = (LuanTable)t; - Object value = tbl.get(key); - if( value != null ) - return value; - h = luan.getHandler("__index",t); - if( h==null ) - return null; - } else { - h = luan.getHandler("__index",t); - if( h==null ) - throw luan.bit(op1.se()).exception( "attempt to index '"+op1.se().text()+"' (a " + Luan.type(t) + " value)" ); - } - if( h instanceof LuanFunction ) { - LuanFunction fn = (LuanFunction)h; - return Luan.first(luan.bit(se).call(fn,"__index",new Object[]{t,key})); - } - return index(luan,h,key); - } -}
--- a/src/luan/impl/LeExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanFunction; -import luan.LuanException; -import luan.LuanSource; -import luan.LuanBit; - - -final class LeExpr extends BinaryOpExpr { - - LeExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object o1 = op1.eval(luan); - Object o2 = op2.eval(luan); - if( o1 instanceof Number && o2 instanceof Number ) { - Number n1 = (Number)o1; - Number n2 = (Number)o2; - return n1.doubleValue() <= n2.doubleValue(); - } - if( o1 instanceof String && o2 instanceof String ) { - String s1 = (String)o1; - String s2 = (String)o2; - return s1.compareTo(s2) <= 0; - } - LuanBit bit = luan.bit(se); - LuanFunction fn = bit.getBinHandler("__le",o1,o2); - if( fn != null ) - return Luan.toBoolean( Luan.first(bit.call(fn,"__le",new Object[]{o1,o2})) ); - fn = bit.getBinHandler("__lt",o1,o2); - if( fn != null ) - return !Luan.toBoolean( Luan.first(bit.call(fn,"__lt",new Object[]{o2,o1})) ); - throw bit.exception( "attempt to compare " + Luan.type(o1) + " with " + Luan.type(o2) ); - } -}
--- a/src/luan/impl/LenExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanException; -import luan.LuanSource; -import luan.LuanBit; - - -final class LenExpr extends UnaryOpExpr { - - LenExpr(LuanSource.Element se,Expr op) { - super(se,op); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object o = op.eval(luan); - if( o instanceof String ) { - String s = (String)o; - return s.length(); - } - if( o instanceof byte[] ) { - byte[] a = (byte[])o; - return a.length; - } - LuanBit bit = luan.bit(se); - LuanFunction fn = bit.getHandlerFunction("__len",o); - if( fn != null ) - return Luan.first(bit.call(fn,"__len",new Object[]{o})); - if( o instanceof LuanTable ) { - LuanTable t = (LuanTable)o; - return t.length(); - } - throw bit.exception( "attempt to get length of a " + Luan.type(o) + " value" ); - } -}
--- a/src/luan/impl/LtExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanFunction; -import luan.LuanException; -import luan.LuanSource; - - -final class LtExpr extends BinaryOpExpr { - - LtExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object o1 = op1.eval(luan); - Object o2 = op2.eval(luan); - return luan.bit(se).isLessThan(o1,o2); - } -}
--- a/src/luan/impl/LuanCompiler.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -package luan.impl; - -import luan.LuanFunction; -import luan.LuanState; -import luan.LuanException; -import luan.LuanSource; -import luan.LuanElement; -import luan.LuanTable; -import java.util.Map; - - -public final class LuanCompiler { - private LuanCompiler() {} // never - - public static LuanFunction compile(LuanState luan,LuanSource src,LuanTable env,boolean allowExpr) throws LuanException { - UpValue.Getter envGetter = env!=null ? new UpValue.ValueGetter(env) : new UpValue.EnvGetter(); - LuanParser parser = new LuanParser(src,envGetter); - for( Map.Entry<Object,Object> entry : luan.global() ) { - Object key = entry.getKey(); - if( key instanceof String ) - parser.addVar( (String)key, entry.getValue() ); - } - FnDef fnDef = parse(luan,parser,allowExpr); - if( env != null ) - return new Closure((LuanStateImpl)luan,fnDef); - final Closure c = new Closure((LuanStateImpl)luan,fnDef); - return new LuanFunction() { - @Override public Object call(LuanState luan,Object[] args) throws LuanException { - Object rtn = c.call(luan,args); - if( rtn instanceof Object[] && ((Object[])rtn).length==0 ) - rtn = c.upValues()[0].get(); - return rtn; - } - }; - } - - private static FnDef parse(LuanState luan,LuanParser parser,boolean allowExpr) throws LuanException { - try { - if( allowExpr ) { - FnDef fnDef = parser.Expression(); - if( fnDef != null ) - return fnDef; - } - return parser.RequiredModule(); - } catch(ParseException e) { -//e.printStackTrace(); - LuanElement le = new LuanSource.CompilerElement(parser.source); - throw luan.bit(le).exception( e.getFancyMessage() ); - } - } - - public static LuanState newLuanState() { - return new LuanStateImpl(); - } -}
--- a/src/luan/impl/LuanParser.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1360 +0,0 @@ -package luan.impl; - -import java.util.Set; -import java.util.HashSet; -import java.util.Arrays; -import java.util.List; -import java.util.ArrayList; -import java.util.Scanner; -import luan.Luan; -import luan.LuanState; -import luan.LuanSource; - - -final class LuanParser { - - private static final class Frame { - final Frame parent; - final List<String> symbols = new ArrayList<String>(); - int stackSize = 0; - int loops = 0; - boolean isVarArg = false; - final List<String> upValueSymbols = new ArrayList<String>(); - final List<UpValue.Getter> upValueGetters = new ArrayList<UpValue.Getter>(); - - Frame(UpValue.Getter envGetter) { - this.parent = null; - upValueSymbols.add(_ENV); - upValueGetters.add(envGetter); - } - - Frame(Frame parent) { - this.parent = parent; - if( upValueIndex(_ENV) != 0 ) - throw new RuntimeException(); - } - - int stackIndex(String name) { - int i = symbols.size(); - while( --i >= 0 ) { - if( symbols.get(i).equals(name) ) - return i; - } - return -1; - } - - int upValueIndex(String name) { - int i = upValueSymbols.size(); - while( --i >= 0 ) { - if( upValueSymbols.get(i).equals(name) ) - return i; - } - if( parent==null ) - return -1; - i = parent.stackIndex(name); - if( i != -1 ) { - upValueGetters.add(new UpValue.StackGetter(i)); - } else { - i = parent.upValueIndex(name); - if( i == -1 ) - return -1; - upValueGetters.add(new UpValue.NestedGetter(i)); - } - upValueSymbols.add(name); - return upValueSymbols.size() - 1; - } - - void addUpValueGetter(String name,UpValue.Getter upValueGetter) { - upValueSymbols.add(name); - upValueGetters.add(upValueGetter); - } - } - - private static class In { - static final In NOTHING = new In(false,false); - - final boolean parens; - final boolean template; - - private In(boolean parens,boolean template) { - this.parens = parens; - this.template = template; - } - - In parens() { - return parens ? this : new In(true,template); - } - - In template() { - return template ? this : new In(parens,true); - } - } - - private static final String _ENV = "_ENV"; - private static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0]; - - final LuanSource source; - private Frame frame; - private final Parser parser; - private final boolean interactive; - - LuanParser(LuanSource source,UpValue.Getter envGetter) { - this.source = source; - this.frame = new Frame(envGetter); - this.parser = new Parser(source); - this.interactive = envGetter instanceof UpValue.ValueGetter; - } - - void addVar(String name,Object value) { - frame.addUpValueGetter(name,new UpValue.ValueGetter(value)); - } - - private LuanSource.Element se(int start) { - return new LuanSource.Element(source,start,parser.currentIndex()); - } - - private List<String> symbols() { - return frame.symbols; - } - - private int symbolsSize() { - return frame.symbols.size(); - } - - private void addSymbol(String name) { - frame.symbols.add(name); - if( frame.stackSize < symbolsSize() ) - frame.stackSize = symbolsSize(); - } - - private void addSymbols(List<String> names) { - frame.symbols.addAll(names); - if( frame.stackSize < symbolsSize() ) - frame.stackSize = symbolsSize(); - } - - private int stackIndex(String name) { - return frame.stackIndex(name); - } - - private void popSymbols(int n) { - List<String> symbols = frame.symbols; - while( n-- > 0 ) { - symbols.remove(symbols.size()-1); - } - } - - private int upValueIndex(String name) { - return frame.upValueIndex(name); - } - - private void incLoops() { - frame.loops++; - } - - private void decLoops() { - frame.loops--; - } - - private <T> T required(T t) throws ParseException { - if( t==null ) - throw parser.exception(); - return t; - } - - private <T> T required(T t,String msg) throws ParseException { - if( t==null ) - throw parser.exception(msg); - return t; - } - - private static Expr expr(Expressions exprs) { - if( exprs instanceof Expr ) - return (Expr)exprs; - return new ExpressionsExpr(exprs); - } - - private FnDef newFnDef(int start,Stmt stmt) { - return new FnDef( se(start), stmt, frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) ); - } - - FnDef Expression() throws ParseException { - Spaces(In.NOTHING); - int start = parser.begin(); - Expressions expr = Expr(In.NOTHING); - if( expr != null && parser.endOfInput() ) { - Stmt stmt = new ReturnStmt( se(start), expr ); - return parser.success(newFnDef(start,stmt)); - } - return parser.failure(null); - } - - FnDef RequiredModule() throws ParseException { - Spaces(In.NOTHING); - int start = parser.begin(); - frame.isVarArg = true; - Stmt stmt = RequiredBlock(); - if( parser.endOfInput() ) - return parser.success(newFnDef(start,stmt)); - throw parser.exception(); - } - - private Stmt RequiredBlock() throws ParseException { - List<Stmt> stmts = new ArrayList<Stmt>(); - int stackStart = symbolsSize(); - Stmt(stmts); - while( StmtSep(stmts) ) { - Spaces(In.NOTHING); - Stmt(stmts); - } - int stackEnd = symbolsSize(); - popSymbols( stackEnd - stackStart ); - if( stmts.isEmpty() ) - return Stmt.EMPTY; - if( stmts.size()==1 && stackStart==stackEnd ) - return stmts.get(0); - return new Block( stmts.toArray(new Stmt[0]), stackStart, stackEnd ); - } - - private boolean StmtSep(List<Stmt> stmts) throws ParseException { - parser.begin(); - if( parser.match( ';' ) ) - return parser.success(); - if( parser.match( "--" ) ) { - while( parser.noneOf("\r\n") ); - } - if( EndOfLine() ) - return parser.success(); - parser.rollback(); - Stmt stmt = TemplateStmt(); - if( stmt != null ) { - stmts.add(stmt); - return parser.success(); - } - return parser.failure(); - } - - private boolean EndOfLine() { - return parser.match( "\r\n" ) || parser.match( '\r' ) || parser.match( '\n' ); - } - - private void Stmt(List<Stmt> stmts) throws ParseException { - if( LocalStmt(stmts) ) - return; - Stmt stmt; - if( (stmt=ReturnStmt()) != null - || (stmt=FunctionStmt()) != null - || (stmt=LocalFunctionStmt()) != null - || (stmt=ImportStmt()) != null - || (stmt=BreakStmt()) != null - || (stmt=ForStmt()) != null - || (stmt=TryStmt()) != null - || (stmt=DoStmt()) != null - || (stmt=WhileStmt()) != null - || (stmt=FunctionStmt()) != null - || (stmt=RepeatStmt()) != null - || (stmt=IfStmt()) != null - || (stmt=SetStmt()) != null - || (stmt=ExpressionsStmt()) != null - ) { - stmts.add(stmt); - } - } - - private Stmt TemplateStmt() throws ParseException { - int start = parser.currentIndex(); - Expressions exp = TemplateExpressions(In.NOTHING); - if( exp == null ) - return null; - Expr fnExp = (Expr)nameVar(start,"Io").expr(); - fnExp = new IndexExpr( se(start), fnExp, new ConstExpr("stdout") ); - fnExp = new IndexExpr( se(start), fnExp, new ConstExpr("write") ); - FnCall fnCall = new FnCall( se(start), fnExp, exp ); - return new ExpressionsStmt(fnCall); - } - - private Expressions TemplateExpressions(In in) throws ParseException { - if( in.template ) - return null; - int start = parser.begin(); - if( !parser.match( "%>" ) ) - return parser.failure(null); - EndOfLine(); - In inTemplate = in.template(); - List<Expressions> builder = new ArrayList<Expressions>(); - while(true) { - if( parser.match( "<%=" ) ) { - Spaces(inTemplate); - builder.add( RequiredExpr(inTemplate) ); - RequiredMatch( "%>" ); - } else if( parser.match( "<%" ) ) { - Spaces(inTemplate); - return parser.success(ExpList.build(builder)); - } else { - int i = parser.currentIndex(); - do { - if( parser.match( "%>" ) ) - throw parser.exception("'%>' unexpected"); - if( !parser.anyChar() ) - throw parser.exception("Unclosed template expression"); - } while( !parser.test( "<%" ) ); - String match = parser.textFrom(i); - builder.add( new ConstExpr(match) ); - } - } - } - - private Stmt ReturnStmt() throws ParseException { - int start = parser.begin(); - if( !Keyword("return",In.NOTHING) ) - return parser.failure(null); - Expressions exprs = ExpList(In.NOTHING); - if( exprs==null ) - exprs = ExpList.emptyExpList; - return parser.success( new ReturnStmt(se(start),exprs) ); - } - - private Stmt FunctionStmt() throws ParseException { - parser.begin(); - if( !Keyword("function",In.NOTHING) ) - return parser.failure(null); - - int start = parser.currentIndex(); - Var var = nameVar(start,RequiredName(In.NOTHING)); - while( parser.match( '.' ) ) { - Spaces(In.NOTHING); - var = indexVar( start, expr(var.expr()), NameExpr(In.NOTHING) ); - } - Settable fnName = var.settable(); - - FnDef fnDef = RequiredFunction(In.NOTHING); - return parser.success( new SetStmt(fnName,fnDef) ); - } - - private Stmt LocalFunctionStmt() throws ParseException { - parser.begin(); - if( !(Keyword("local",In.NOTHING) && Keyword("function",In.NOTHING)) ) - return parser.failure(null); - String name = RequiredName(In.NOTHING); - addSymbol( name ); - FnDef fnDef = RequiredFunction(In.NOTHING); - return parser.success( new SetStmt( new SetLocalVar(symbolsSize()-1), fnDef ) ); - } - - private Stmt ImportStmt() throws ParseException { - int start = parser.begin(); - if( !Keyword("import",In.NOTHING) ) - return parser.failure(null); - Expr importExpr = (Expr)nameVar(start,"require").expr(); - String modName = StringLiteral(In.NOTHING); - if( modName==null ) - return parser.failure(null); - String varName = modName.substring(modName.lastIndexOf('.')+1); - LuanSource.Element se = se(start); - FnCall require = new FnCall( se, importExpr, new ConstExpr(modName) ); - Settable settable; - if( interactive ) { - settable = nameVar(se,varName).settable(); - } else { - addSymbol( varName ); - settable = new SetLocalVar(symbolsSize()-1); - } - return parser.success( new SetStmt( settable, expr(require) ) ); - } - - private Stmt BreakStmt() throws ParseException { - parser.begin(); - if( !Keyword("break",In.NOTHING) ) - return parser.failure(null); - if( frame.loops <= 0 ) - throw parser.exception("'break' outside of loop"); - return parser.success( new BreakStmt() ); - } - - private Stmt ForStmt() throws ParseException { - int start = parser.begin(); - int stackStart = symbolsSize(); - if( !Keyword("for",In.NOTHING) ) - return parser.failure(null); - List<String> names = RequiredNameList(In.NOTHING); - if( !Keyword("in",In.NOTHING) ) - return parser.failure(null); - Expr expr = expr(RequiredExpr(In.NOTHING)); - RequiredKeyword("do",In.NOTHING); - addSymbols(names); - Stmt loop = RequiredLoopBlock(); - RequiredKeyword("end",In.NOTHING); - Stmt stmt = new ForStmt( se(start), stackStart, symbolsSize() - stackStart, expr, loop ); - popSymbols( symbolsSize() - stackStart ); - return parser.success(stmt); - } - - private Stmt TryStmt() throws ParseException { - parser.begin(); - if( !Keyword("try",In.NOTHING) ) - return parser.failure(null); - Stmt tryBlock = RequiredBlock(); - RequiredKeyword("catch",In.NOTHING); - String name = RequiredName(In.NOTHING); - addSymbol(name); - RequiredKeyword("do",In.NOTHING); - Stmt catchBlock = RequiredBlock(); - RequiredKeyword("end",In.NOTHING); - Stmt stmt = new TryStmt( tryBlock, symbolsSize()-1, catchBlock ); - popSymbols(1); - return parser.success(stmt); - } - - private Stmt DoStmt() throws ParseException { - parser.begin(); - if( !Keyword("do",In.NOTHING) ) - return parser.failure(null); - Stmt stmt = RequiredBlock(); - RequiredKeyword("end",In.NOTHING); - return parser.success(stmt); - } - - private boolean LocalStmt(List<Stmt> stmts) throws ParseException { - parser.begin(); - if( !Keyword("local",In.NOTHING) ) - return parser.failure(); - List<String> names = NameList(In.NOTHING); - if( names==null ) - return parser.failure(); - if( parser.match( '=' ) ) { - Spaces(In.NOTHING); - Expressions values = ExpList(In.NOTHING); - if( values==null ) - throw parser.exception("Expressions expected"); - SetLocalVar[] vars = new SetLocalVar[names.size()]; - int stackStart = symbolsSize(); - for( int i=0; i<vars.length; i++ ) { - vars[i] = new SetLocalVar(stackStart+i); - } - stmts.add( new SetStmt( vars, values ) ); - } - addSymbols(names); - return parser.success(); - } - - private List<String> RequiredNameList(In in) throws ParseException { - parser.begin(); - List<String> names = NameList(in); - if( names==null ) - throw parser.exception("Name expected"); - return parser.success(names); - } - - private List<String> NameList(In in) throws ParseException { - String name = Name(in); - if( name==null ) - return null; - List<String> names = new ArrayList<String>(); - names.add(name); - while( (name=anotherName(in)) != null ) { - names.add(name); - } - return names; - } - - private String anotherName(In in) throws ParseException { - parser.begin(); - if( !parser.match( ',' ) ) - return parser.failure(null); - Spaces(in); - String name = Name(in); - if( name==null ) - return parser.failure(null); - return parser.success(name); - } - - private Stmt WhileStmt() throws ParseException { - int start = parser.begin(); - if( !Keyword("while",In.NOTHING) ) - return parser.failure(null); - Expr cnd = expr(RequiredExpr(In.NOTHING)); - RequiredKeyword("do",In.NOTHING); - Stmt loop = RequiredLoopBlock(); - RequiredKeyword("end",In.NOTHING); - return parser.success( new WhileStmt(se(start),cnd,loop) ); - } - - private Stmt RepeatStmt() throws ParseException { - int start = parser.begin(); - if( !Keyword("repeat",In.NOTHING) ) - return parser.failure(null); - Stmt loop = RequiredLoopBlock(); - RequiredKeyword("until",In.NOTHING); - Expr cnd = expr(RequiredExpr(In.NOTHING)); - return parser.success( new RepeatStmt(se(start),loop,cnd) ); - } - - private Stmt RequiredLoopBlock() throws ParseException { - incLoops(); - Stmt stmt = RequiredBlock(); - decLoops(); - return stmt; - } - - private Stmt IfStmt() throws ParseException { - parser.begin(); - if( !Keyword("if",In.NOTHING) ) - return parser.failure(null); - return parser.success( IfStmt2() ); - } - - private Stmt IfStmt2() throws ParseException { - int start = parser.currentIndex(); - Expr cnd = expr(RequiredExpr(In.NOTHING)); - RequiredKeyword("then",In.NOTHING); - Stmt thenBlock = RequiredBlock(); - Stmt elseBlock; - if( Keyword("elseif",In.NOTHING) ) { - elseBlock = IfStmt2(); - } else { - elseBlock = Keyword("else",In.NOTHING) ? RequiredBlock() : Stmt.EMPTY; - RequiredKeyword("end",In.NOTHING); - } - return new IfStmt(se(start),cnd,thenBlock,elseBlock); - } - - private Stmt SetStmt() throws ParseException { - parser.begin(); - List<Settable> vars = new ArrayList<Settable>(); - Settable s = SettableVar(); - if( s == null ) - return parser.failure(null); - vars.add(s); - while( parser.match( ',' ) ) { - Spaces(In.NOTHING); - s = SettableVar(); - if( s == null ) - return parser.failure(null); - vars.add(s); - } - if( !parser.match( '=' ) ) - return parser.failure(null); - Spaces(In.NOTHING); - Expressions values = ExpList(In.NOTHING); - if( values==null ) - throw parser.exception("Expressions expected"); - return parser.success( new SetStmt( vars.toArray(new Settable[0]), values ) ); - } - - private Stmt ExpressionsStmt() throws ParseException { - parser.begin(); - Expressions exp = Expr(In.NOTHING); - if( exp instanceof FnCall || exp instanceof AndExpr || exp instanceof OrExpr ) - return parser.success( new ExpressionsStmt(exp) ); - return parser.failure(null); - } - - private Settable SettableVar() throws ParseException { - int start = parser.begin(); - Var var = VarZ(In.NOTHING); - if( var==null ) - return parser.failure(null); - return parser.success( var.settable() ); - } - - private Expressions RequiredExpr(In in) throws ParseException { - parser.begin(); - return parser.success(required(Expr(in),"Bad expression")); - } - - private Expressions Expr(In in) throws ParseException { - parser.begin(); - Expressions exp; - return (exp = VarArgs(in)) != null - || (exp = OrExpr(in)) != null - ? parser.success(exp) - : parser.failure((Expressions)null) - ; - } - - private Expressions OrExpr(In in) throws ParseException { - int start = parser.begin(); - Expressions exp = AndExpr(in); - if( exp==null ) - return parser.failure(null); - while( Keyword("or",in) ) { - exp = new OrExpr( se(start), expr(exp), required(expr(AndExpr(in))) ); - } - return parser.success(exp); - } - - private Expressions AndExpr(In in) throws ParseException { - int start = parser.begin(); - Expressions exp = RelExpr(in); - if( exp==null ) - return parser.failure(null); - while( Keyword("and",in) ) { - exp = new AndExpr( se(start), expr(exp), required(expr(RelExpr(in))) ); - } - return parser.success(exp); - } - - private Expressions RelExpr(In in) throws ParseException { - int start = parser.begin(); - Expressions exp = ConcatExpr(in); - if( exp==null ) - return parser.failure(null); - while(true) { - if( parser.match("==") ) { - Spaces(in); - exp = new EqExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ); - } else if( parser.match("~=") ) { - Spaces(in); - exp = new NotExpr( se(start), new EqExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ) ); - } else if( parser.match("<=") ) { - Spaces(in); - exp = new LeExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ); - } else if( parser.match(">=") ) { - Spaces(in); - exp = new LeExpr( se(start), required(expr(ConcatExpr(in))), expr(exp) ); - } else if( parser.match("<") ) { - Spaces(in); - exp = new LtExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ); - } else if( parser.match(">") ) { - Spaces(in); - exp = new LtExpr( se(start), required(expr(ConcatExpr(in))), expr(exp) ); - } else - break; - } - return parser.success(exp); - } - - private Expressions ConcatExpr(In in) throws ParseException { - int start = parser.begin(); - Expressions exp = SumExpr(in); - if( exp==null ) - return parser.failure(null); - if( parser.match("..") ) { - Spaces(in); - exp = new ConcatExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ); - } - return parser.success(exp); - } - - private Expressions SumExpr(In in) throws ParseException { - int start = parser.begin(); - Expressions exp = TermExpr(in); - if( exp==null ) - return parser.failure(null); - while(true) { - if( parser.match('+') ) { - Spaces(in); - exp = new AddExpr( se(start), expr(exp), required(expr(TermExpr(in))) ); - } else if( Minus() ) { - Spaces(in); - exp = new SubExpr( se(start), expr(exp), required(expr(TermExpr(in))) ); - } else - break; - } - return parser.success(exp); - } - - private boolean Minus() { - parser.begin(); - return parser.match('-') && !parser.match('-') ? parser.success() : parser.failure(); - } - - private Expressions TermExpr(In in) throws ParseException { - int start = parser.begin(); - Expressions exp = UnaryExpr(in); - if( exp==null ) - return parser.failure(null); - while(true) { - if( parser.match('*') ) { - Spaces(in); - exp = new MulExpr( se(start), expr(exp), required(expr(UnaryExpr(in))) ); - } else if( parser.match('/') ) { - Spaces(in); - exp = new DivExpr( se(start), expr(exp), required(expr(UnaryExpr(in))) ); - } else if( Mod() ) { - Spaces(in); - exp = new ModExpr( se(start), expr(exp), required(expr(UnaryExpr(in))) ); - } else - break; - } - return parser.success(exp); - } - - private boolean Mod() { - parser.begin(); - return parser.match('%') && !parser.match('>') ? parser.success() : parser.failure(); - } - - private Expressions UnaryExpr(In in) throws ParseException { - int start = parser.begin(); - if( parser.match('#') ) { - Spaces(in); - return parser.success( new LenExpr( se(start), required(expr(UnaryExpr(in))) ) ); - } - if( Minus() ) { - Spaces(in); - return parser.success( new UnmExpr( se(start), required(expr(UnaryExpr(in))) ) ); - } - if( Keyword("not",in) ) { - Spaces(in); - return parser.success( new NotExpr( se(start), required(expr(UnaryExpr(in))) ) ); - } - Expressions exp = PowExpr(in); - if( exp==null ) - return parser.failure(null); - return parser.success(exp); - } - - private Expressions PowExpr(In in) throws ParseException { - int start = parser.begin(); - Expressions exp = SingleExpr(in); - if( exp==null ) - return parser.failure(null); - if( parser.match('^') ) { - Spaces(in); - exp = new ConcatExpr( se(start), expr(exp), required(expr(PowExpr(in))) ); - } - return parser.success(exp); - } - - private Expressions SingleExpr(In in) throws ParseException { - parser.begin(); - Expressions exp; - exp = FunctionExpr(in); - if( exp != null ) - return parser.success(exp); - exp = TableExpr(in); - if( exp != null ) - return parser.success(exp); - exp = VarExp(in); - if( exp != null ) - return parser.success(exp); - exp = Literal(in); - if( exp != null ) - return parser.success(exp); - return parser.failure(null); - } - - private Expr FunctionExpr(In in) throws ParseException { - if( !Keyword("function",in) ) - return null; - return RequiredFunction(in); - } - - private FnDef RequiredFunction(In in) throws ParseException { - int start = parser.begin(); - RequiredMatch('('); - In inParens = in.parens(); - Spaces(inParens); - frame = new Frame(frame); - List<String> names = NameList(in); - if( names != null ) { - addSymbols(names); - if( parser.match(',') ) { - Spaces(inParens); - if( !parser.match("...") ) - throw parser.exception(); - frame.isVarArg = true; - } - } else if( parser.match("...") ) { - Spaces(inParens); - frame.isVarArg = true; - } - RequiredMatch(')'); - Spaces(in); - Stmt block = RequiredBlock(); - RequiredKeyword("end",in); - FnDef fnDef = newFnDef(start,block); - frame = frame.parent; - return parser.success(fnDef); - } - - private VarArgs VarArgs(In in) throws ParseException { - int start = parser.begin(); - if( !frame.isVarArg || !parser.match("...") ) - return parser.failure(null); - Spaces(in); - return parser.success( new VarArgs(se(start)) ); - } - - private Expr TableExpr(In in) throws ParseException { - int start = parser.begin(); - if( !parser.match('{') ) - return parser.failure(null); - In inParens = in.parens(); - Spaces(inParens); - List<TableExpr.Field> fields = new ArrayList<TableExpr.Field>(); - List<Expressions> builder = new ArrayList<Expressions>(); - while( Field(fields,builder,in) && FieldSep(inParens) ); - Spaces(inParens); - if( !parser.match('}') ) - throw parser.exception("Expected table element or '}'"); - return parser.success( new TableExpr( se(start), fields.toArray(new TableExpr.Field[0]), ExpList.build(builder) ) ); - } - - private boolean FieldSep(In in) throws ParseException { - if( !parser.anyOf(",;") ) - return false; - Spaces(in); - return true; - } - - private boolean Field(List<TableExpr.Field> fields,List<Expressions> builder,In in) throws ParseException { - parser.begin(); - Expr exp = SubExpr(in); - if( exp==null ) - exp = NameExpr(in); - if( exp!=null && parser.match('=') ) { - Spaces(in); - fields.add( new TableExpr.Field( exp, required(expr(Expr(in))) ) ); - return parser.success(); - } - parser.rollback(); - Expressions exprs = Expr(in); - if( exprs != null ) { - builder.add(exprs); - return parser.success(); - } - return parser.failure(); - } - - private Expressions VarExp(In in) throws ParseException { - Var var = VarZ(in); - return var==null ? null : var.expr(); - } - - private Var VarZ(In in) throws ParseException { - int start = parser.begin(); - Var var = VarStart(in); - if( var==null ) - return parser.failure(null); - Var var2; - while( (var2=Var2(in,start,var.expr())) != null ) { - var = var2; - } - return parser.success(var); - } - - private Var Var2(In in,int start,Expressions exp1) throws ParseException { - parser.begin(); - Var var = VarExt(in,start,exp1); - if( var != null ) - return parser.success(var); - if( parser.match("->") ) { - Spaces(in); - List<Expressions> builder = new ArrayList<Expressions>(); - builder.add(exp1); - Expr exp2 = expr(RequiredVarExpB(in)); - FnCall fnCall = required(Args( in, start, exp2, builder )); - return parser.success(exprVar(fnCall)); - } - FnCall fnCall = Args( in, start, expr(exp1), new ArrayList<Expressions>() ); - if( fnCall != null ) - return parser.success(exprVar(fnCall)); - return parser.failure(null); - } - - private Expressions RequiredVarExpB(In in) throws ParseException { - int start = parser.begin(); - Var var = required(VarStart(in)); - Var var2; - while( (var2=VarExt(in,start,var.expr())) != null ) { - var = var2; - } - return parser.success(var.expr()); - } - - private Var VarExt(In in,int start,Expressions exp1) throws ParseException { - parser.begin(); - Expr exp2 = SubExpr(in); - if( exp2 != null ) - return parser.success(indexVar(start,expr(exp1),exp2)); - if( parser.match('.') ) { - Spaces(in); - exp2 = NameExpr(in); - if( exp2!=null ) - return parser.success(indexVar(start,expr(exp1),exp2)); - } - return parser.failure(null); - } - - private Var VarStart(In in) throws ParseException { - int start = parser.begin(); - if( parser.match('(') ) { - In inParens = in.parens(); - Spaces(inParens); - Expr exp = expr(RequiredExpr(inParens)); - RequiredMatch(')'); - Spaces(in); - return parser.success(exprVar(exp)); - } - String name = Name(in); - if( name != null ) - return parser.success(nameVar(start,name)); - return parser.failure(null); - } - - private Expr env() { - int index = stackIndex(_ENV); - if( index != -1 ) - return new GetLocalVar(null,index); - index = upValueIndex(_ENV); - if( index != -1 ) - return new GetUpVar(null,index); - throw new RuntimeException("_ENV not found"); - } - - private interface Var { - public Expressions expr(); - public Settable settable(); - } - - private Var nameVar(final int start,final String name) { - return nameVar(se(start),name); - } - - private Var nameVar(final LuanSource.Element se,final String name) { - return new Var() { - - public Expr expr() { - int index = stackIndex(name); - if( index != -1 ) - return new GetLocalVar(se,index); - index = upValueIndex(name); - if( index != -1 ) - return new GetUpVar(se,index); - return new IndexExpr( se, env(), new ConstExpr(name) ); - } - - public Settable settable() { - int index = stackIndex(name); - if( index != -1 ) - return new SetLocalVar(index); - index = upValueIndex(name); - if( index != -1 ) - return new SetUpVar(index); - return new SetTableEntry( se, env(), new ConstExpr(name) ); - } - }; - } - - private Var exprVar(final Expressions expr) { - return new Var() { - - public Expressions expr() { - return expr; - } - - public Settable settable() { - return null; - } - }; - } - - private Var indexVar(final int start,final Expr table,final Expr key) { - return new Var() { - - public Expr expr() { - return new IndexExpr( se(start), table, key ); - } - - public Settable settable() { - return new SetTableEntry(se(start),table,key); - } - }; - } - - private FnCall Args(In in,int start,Expr fn,List<Expressions> builder) throws ParseException { - parser.begin(); - return args(in,builder) - ? parser.success( new FnCall( se(start), fn, ExpList.build(builder) ) ) - : parser.failure((FnCall)null); - } - - private boolean args(In in,List<Expressions> builder) throws ParseException { - if( parser.match('(') ) { - In inParens = in.parens(); - Spaces(inParens); - ExpList(inParens,builder); // optional - if( !parser.match(')') ) - throw parser.exception("Expression or ')' expected"); - Spaces(in); - return true; - } - Expr exp = TableExpr(in); - if( exp != null ) { - builder.add(exp); - return true; - } - String s = StringLiteral(in); - if( s != null ) { - builder.add( new ConstExpr(s) ); - return true; - } - Expressions exps = TemplateExpressions(in); - if( exps != null ) { - builder.add(exps); - return true; - } - return false; - } - - private Expressions ExpList(In in) throws ParseException { - List<Expressions> builder = new ArrayList<Expressions>(); - return ExpList(in,builder) ? ExpList.build(builder) : null; - } - - private boolean ExpList(In in,List<Expressions> builder) throws ParseException { - parser.begin(); - Expressions exp = TemplateExpressions(in); - if( exp != null ) { - builder.add(exp); - return parser.success(); - } - exp = Expr(in); - if( exp==null ) - return parser.failure(); - builder.add(exp); - while( parser.match(',') ) { - Spaces(in); - exp = TemplateExpressions(in); - if( exp != null ) { - builder.add(exp); - return parser.success(); - } - builder.add( RequiredExpr(in) ); - } - return parser.success(); - } - - private Expr SubExpr(In in) throws ParseException { - parser.begin(); - if( !parser.match('[') ) - return parser.failure(null); - In inParens = in.parens(); - Spaces(inParens); - Expr exp = expr(RequiredExpr(inParens)); - RequiredMatch(']'); - Spaces(in); - return parser.success(exp); - } - - private Expr NameExpr(In in) throws ParseException { - String name = Name(in); - return name==null ? null : new ConstExpr(name); - } - - private String RequiredName(In in) throws ParseException { - parser.begin(); - String name = Name(in); - if( name==null ) - throw parser.exception("Name expected"); - return parser.success(name); - } - - private String Name(In in) throws ParseException { - int start = parser.begin(); - if( !NameFirstChar() ) - return parser.failure(null); - while( NameChar() ); - String match = parser.textFrom(start); - if( keywords.contains(match) ) - return parser.failure(null); - Spaces(in); - return parser.success(match); - } - - private boolean NameChar() { - return NameFirstChar() || Digit(); - } - - private boolean NameFirstChar() { - return parser.inCharRange('a', 'z') || parser.inCharRange('A', 'Z') || parser.match('_'); - } - - private void RequiredMatch(char c) throws ParseException { - if( !parser.match(c) ) - throw parser.exception("'"+c+"' expected"); - } - - private void RequiredMatch(String s) throws ParseException { - if( !parser.match(s) ) - throw parser.exception("'"+s+"' expected"); - } - - private void RequiredKeyword(String keyword,In in) throws ParseException { - if( !Keyword(keyword,in) ) - throw parser.exception("'"+keyword+"' expected"); - } - - private boolean Keyword(String keyword,In in) throws ParseException { - parser.begin(); - if( !parser.match(keyword) || NameChar() ) - return parser.failure(); - Spaces(in); - return parser.success(); - } - - private static final Set<String> keywords = new HashSet<String>(Arrays.asList( - "and", - "break", - "catch", - "do", - "else", - "elseif", - "end", - "false", - "for", - "function", - "goto", - "if", - "import", - "in", - "local", - "nil", - "not", - "or", - "repeat", - "return", - "then", - "true", - "try", - "until", - "while" - )); - - private Expr Literal(In in) throws ParseException { - if( NilLiteral(in) ) - return new ConstExpr(null); - Boolean b = BooleanLiteral(in); - if( b != null ) - return new ConstExpr(b); - Number n = NumberLiteral(in); - if( n != null ) - return new ConstExpr(n); - String s = StringLiteral(in); - if( s != null ) - return new ConstExpr(s); - return null; - } - - private boolean NilLiteral(In in) throws ParseException { - return Keyword("nil",in); - } - - private Boolean BooleanLiteral(In in) throws ParseException { - if( Keyword("true",in) ) - return true; - if( Keyword("false",in) ) - return false; - return null; - } - - private Number NumberLiteral(In in) throws ParseException { - parser.begin(); - Number n; - if( parser.matchIgnoreCase("0x") ) { - n = HexNumber(); - } else { - n = DecNumber(); - } - if( n==null || NameChar() ) - return parser.failure(null); - Spaces(in); - return parser.success(n); - } - - private Number DecNumber() { - int start = parser.begin(); - if( Int() ) { - if( parser.match('.') ) - Int(); // optional - } else if( parser.match('.') && Int() ) { - // ok - } else - return parser.failure(null); - Exponent(); // optional - return parser.success(Double.valueOf(parser.textFrom(start))); - } - - private boolean Exponent() { - parser.begin(); - if( !parser.matchIgnoreCase("e") ) - return parser.failure(); - parser.anyOf("+-"); // optional - if( !Int() ) - return parser.failure(); - return parser.success(); - } - - private boolean Int() { - if( !Digit() ) - return false; - while( Digit() ); - return true; - } - - private boolean Digit() { - return parser.inCharRange('0', '9'); - } - - private Number HexNumber() { - int start = parser.begin(); - double n; - if( HexInt() ) { - n = (double)Long.parseLong(parser.textFrom(start),16); - if( parser.match('.') ) { - start = parser.currentIndex(); - if( HexInt() ) { - String dec = parser.textFrom(start); - n += (double)Long.parseLong(dec,16) / Math.pow(16,dec.length()); - } - } - } else if( parser.match('.') && HexInt() ) { - String dec = parser.textFrom(start+1); - n = (double)Long.parseLong(dec,16) / Math.pow(16,dec.length()); - } else { - return parser.failure(null); - } - if( parser.matchIgnoreCase("p") ) { - parser.anyOf("+-"); // optional - start = parser.currentIndex(); - if( !HexInt() ) - return parser.failure(null); - n *= Math.pow(2,(double)Long.parseLong(parser.textFrom(start))); - } - return parser.success(Double.valueOf(n)); - } - - private boolean HexInt() { - if( !HexDigit() ) - return false; - while( HexDigit() ); - return true; - } - - - private boolean HexDigit() { - return Digit() || parser.anyOf("abcdefABCDEF"); - } - - private String StringLiteral(In in) throws ParseException { - String s; - if( (s=QuotedString('"'))==null - && (s=QuotedString('\''))==null - && (s=LongString())==null - ) - return null; - Spaces(in); - return s; - } - - private String LongString() throws ParseException { - parser.begin(); - if( !parser.match('[') ) - return parser.failure(null); - int start = parser.currentIndex(); - while( parser.match('=') ); - int nEquals = parser.currentIndex() - start; - if( !parser.match('[') ) - return parser.failure(null); - EndOfLine(); - start = parser.currentIndex(); - while( !LongBracketsEnd(nEquals) ) { - if( !parser.anyChar() ) - throw parser.exception("Unclosed long string"); - } - String s = parser.text.substring( start, parser.currentIndex() - nEquals - 2 ); - return parser.success(s); - } - - private String QuotedString(char quote) throws ParseException { - parser.begin(); - if( !parser.match(quote) ) - return parser.failure(null); - StringBuilder buf = new StringBuilder(); - while( !parser.match(quote) ) { - Character c = EscSeq(); - if( c != null ) { - buf.append(c); - } else { - if( !parser.anyChar() ) - throw parser.exception("Unclosed string"); - buf.append(parser.lastChar()); - } - } - return parser.success(buf.toString()); - } - - private Character EscSeq() { - parser.begin(); - if( !parser.match('\\') ) - return parser.failure(null); - if( parser.match('a') ) return parser.success('\u0007'); - if( parser.match('b') ) return parser.success('\b'); - if( parser.match('f') ) return parser.success('\f'); - if( parser.match('n') ) return parser.success('\n'); - if( parser.match('r') ) return parser.success('\r'); - if( parser.match('t') ) return parser.success('\t'); - if( parser.match('v') ) return parser.success('\u000b'); - if( parser.match('\\') ) return parser.success('\\'); - if( parser.match('"') ) return parser.success('"'); - if( parser.match('\'') ) return parser.success('\''); - int start = parser.currentIndex(); - if( parser.match('x') && HexDigit() && HexDigit() ) - return parser.success((char)Integer.parseInt(parser.textFrom(start+1),16)); - if( Digit() ) { - if( Digit() ) Digit(); // optional - return parser.success((char)Integer.parseInt(parser.textFrom(start))); - } - return parser.failure(null); - } - - private void Spaces(In in) throws ParseException { - while( parser.anyOf(" \t") || Comment() || ContinueOnNextLine() || in.parens && NewLine() ); - } - - private boolean ContinueOnNextLine() { - parser.begin(); - return parser.match('\\') && EndOfLine() ? parser.success() : parser.failure(); - } - - private boolean NewLine() { - if( !EndOfLine() ) - return false; - if( parser.match("--") ) { - while( parser.noneOf("\r\n") ); - } - return true; - } - - private boolean Comment() throws ParseException { - parser.begin(); - if( !parser.match("--[") ) - return parser.failure(); - int start = parser.currentIndex(); - while( parser.match('=') ); - int nEquals = parser.currentIndex() - start; - if( !parser.match('[') ) - return parser.failure(); - while( !LongBracketsEnd(nEquals) ) { - if( !parser.anyChar() ) - throw parser.exception("Unclosed comment"); - } - return parser.success(); - } - - private boolean LongBracketsEnd(int nEquals) { - parser.begin(); - if( !parser.match(']') ) - return parser.failure(); - while( nEquals-- > 0 ) { - if( !parser.match('=') ) - return parser.failure(); - } - if( !parser.match(']') ) - return parser.failure(); - return parser.success(); - } - -}
--- a/src/luan/impl/LuanStateImpl.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -package luan.impl; - -import java.util.List; -import java.util.ArrayList; -import java.util.Map; -import java.util.HashMap; -import luan.Luan; -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.MetatableGetter; -import luan.LuanException; -import luan.LuanElement; -import luan.DeepCloner; - - -final class LuanStateImpl extends LuanState { - - private static class Frame { - final Frame previousFrame; - final Closure closure; - final Object[] stack; - final Object[] varArgs; - UpValue[] downValues = null; - - Frame( Frame previousFrame, Closure closure, int stackSize, Object[] varArgs) { - this.previousFrame = previousFrame; - this.closure = closure; - this.stack = new Object[stackSize]; - this.varArgs = varArgs; - } - - void stackClear(int start,int end) { - if( downValues != null ) { - for( int i=start; i<end; i++ ) { - UpValue downValue = downValues[i]; - if( downValue != null ) { - downValue.close(); - downValues[i] = null; - } - } - } - for( int i=start; i<end; i++ ) { - stack[i] = null; - } - } - - UpValue getUpValue(int index) { - if( downValues==null ) - downValues = new UpValue[stack.length]; - if( downValues[index] == null ) - downValues[index] = new UpValue(stack,index); - return downValues[index]; - } - } - - private Frame frame = null; - Object returnValues; - Closure tailFn; - Map<UpValue.EnvGetter,UpValue> envs = new HashMap<UpValue.EnvGetter,UpValue>(); - - LuanStateImpl() {} - - private LuanStateImpl(LuanStateImpl luan) { - super(luan); - } - - @Override public LuanState shallowClone() { -// if( frame != null ) -// throw new IllegalStateException("frame isn't null"); - return new LuanStateImpl(this); - } - - @Override public void deepenClone(LuanState clone,DeepCloner cloner) { - super.deepenClone(clone,cloner); - LuanStateImpl cloneImpl = (LuanStateImpl)clone; - cloneImpl.envs = new HashMap<UpValue.EnvGetter,UpValue>(); - for( Map.Entry<UpValue.EnvGetter,UpValue> entry : envs.entrySet() ) { - cloneImpl.envs.put( entry.getKey(), cloner.deepClone(entry.getValue()) ); - } - } - - // returns stack - Object[] newFrame(Closure closure, int stackSize, Object[] varArgs) { - returnValues = LuanFunction.NOTHING; - tailFn = null; - frame = new Frame(frame,closure,stackSize,varArgs); - return frame.stack; - } - - void popFrame() { - returnValues = LuanFunction.NOTHING; - tailFn = null; - frame = frame.previousFrame; - } - - Object stackGet(int index) { - return frame.stack[index]; - } - - void stackSet(int index,Object value) { - frame.stack[index] = value; - } - - void stackClear(int start,int end) { - frame.stackClear(start,end); - } - - Object[] varArgs() { - return frame.varArgs; - } - - Closure closure() { - return frame.closure; - } - - UpValue getUpValue(int index) { - return frame.getUpValue(index); - } - - UpValue getUpValue(UpValue.EnvGetter getter) throws LuanException { - UpValue uv = envs.get(getter); - if( uv == null ) { - LuanTable env = new LuanTable(); - uv = new UpValue(env); - envs.put(getter,uv); - } - return uv; - } - - @Override public LuanTable currentEnvironment() { - if( frame==null ) - return null; - return (LuanTable)frame.closure.upValues()[0].get(); - } - -}
--- a/src/luan/impl/ModExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class ModExpr extends BinaryOpExpr { - - ModExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object o1 = op1.eval(luan); - Object o2 = op2.eval(luan); - Number n1 = Luan.toNumber(o1); - Number n2 = Luan.toNumber(o2); - if( n1 != null && n2 != null ) - return n1.doubleValue() % n2.doubleValue(); - return arithmetic(luan,"__mod",o1,o2); - } -}
--- a/src/luan/impl/MulExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class MulExpr extends BinaryOpExpr { - - MulExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object o1 = op1.eval(luan); - Object o2 = op2.eval(luan); - Number n1 = Luan.toNumber(o1); - Number n2 = Luan.toNumber(o2); - if( n1 != null && n2 != null ) - return n1.doubleValue() * n2.doubleValue(); - return arithmetic(luan,"__mul",o1,o2); - } -}
--- a/src/luan/impl/NotExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class NotExpr extends UnaryOpExpr { - - NotExpr(LuanSource.Element se,Expr op) { - super(se,op); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - return !Luan.toBoolean(op.eval(luan)); - } -}
--- a/src/luan/impl/OrExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class OrExpr extends BinaryOpExpr { - - OrExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object v1 = op1.eval(luan); - return Luan.toBoolean(v1) ? v1 : op2.eval(luan); - } -}
--- a/src/luan/impl/ParseException.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -package luan.impl; - -import luan.LuanSource; - - -public final class ParseException extends Exception { - public final LuanSource src; - public final int iCurrent; - public final int iHigh; - - ParseException(String msg,LuanSource src,int iCurrent,int iHigh) { - super(msg); - this.src = src; - this.iCurrent = iCurrent; - this.iHigh = iHigh; -//System.out.println("iCurrent = "+iCurrent); -//System.out.println("iHigh = "+iHigh); - } - - private class Location { - final int line; - final int pos; - - Location(int index) { - int line = 0; - int i = -1; - while(true) { - int j = src.text.indexOf('\n',i+1); - if( j == -1 || j >= index ) - break; - i = j; - line++; - } - this.line = line; - this.pos = index - i - 1; - } - } - - private String[] lines() { - return src.text.split("\n",-1); - } - - public String getFancyMessage() { - Location loc = new Location(iCurrent); - String line = lines()[loc.line]; - String msg = getMessage() + " (line " + (loc.line+1) + ", pos " + (loc.pos+1) + ") in " + src.name + "\n"; - StringBuilder sb = new StringBuilder(msg); - sb.append( line + "\n" ); - for( int i=0; i<loc.pos; i++ ) { - sb.append( line.charAt(i)=='\t' ? '\t' : ' ' ); - } - sb.append("^\n"); - return sb.toString(); - } -}
--- a/src/luan/impl/Parser.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -package luan.impl; - -import luan.LuanSource; - - -final class Parser { - private final LuanSource src; - public final String text; - private final int len; - private int[] stack = new int[256]; - private int frame = 0; - private int iHigh; - - public Parser(LuanSource src) { - this.src = src; - this.text = src.text; - this.len = text.length(); - } - - private int i() { - return stack[frame]; - } - - private void i(int i) { - stack[frame] += i; - if( iHigh < stack[frame] ) - iHigh = stack[frame]; - } - - public int begin() { - frame++; - if( frame == stack.length ) { - int[] a = new int[2*frame]; - System.arraycopy(stack,0,a,0,frame); - stack = a; - } - stack[frame] = stack[frame-1]; - return i(); - } - - public void rollback() { - stack[frame] = stack[frame-1]; - } - - public <T> T success(T t) { - success(); - return t; - } - - public boolean success() { - frame--; - stack[frame] = stack[frame+1]; - return true; - } - - public <T> T failure(T t) { - failure(); - return t; - } - - public boolean failure() { - frame--; - return false; - } - - public ParseException exception(String msg) { - return new ParseException(msg,src,i(),iHigh); - } - - public ParseException exception() { - return exception("Invalid input"); - } - - public int currentIndex() { - return i(); - } - - public char lastChar() { - return text.charAt(i()-1); - } - - public char currentChar() { - return text.charAt(i()); - } - - public boolean endOfInput() { - return i() >= len; - } - - public boolean match(char c) { - if( endOfInput() || text.charAt(i()) != c ) - return false; - i(1); - return true; - } - - public boolean match(String s) { - int n = s.length(); - if( !text.regionMatches(i(),s,0,n) ) - return false; - i(n); - return true; - } - - public boolean matchIgnoreCase(String s) { - int n = s.length(); - if( !text.regionMatches(true,i(),s,0,n) ) - return false; - i(n); - return true; - } - - public boolean anyOf(String s) { - if( endOfInput() || s.indexOf(text.charAt(i())) == -1 ) - return false; - i(1); - return true; - } - - public boolean noneOf(String s) { - if( endOfInput() || s.indexOf(text.charAt(i())) != -1 ) - return false; - i(1); - return true; - } - - public boolean inCharRange(char cLow, char cHigh) { - if( endOfInput() ) - return false; - char c = text.charAt(i()); - if( !(cLow <= c && c <= cHigh) ) - return false; - i(1); - return true; - } - - public boolean anyChar() { - if( endOfInput() ) - return false; - i(1); - return true; - } - - public boolean test(String s) { - return text.regionMatches(i(),s,0,s.length()); - } - - public String textFrom(int start) { - return text.substring(start,i()); - } - -}
--- a/src/luan/impl/PowExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class PowExpr extends BinaryOpExpr { - - PowExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object o1 = op1.eval(luan); - Object o2 = op2.eval(luan); - Number n1 = Luan.toNumber(o1); - Number n2 = Luan.toNumber(o2); - if( n1 != null && n2 != null ) - return Math.pow( n1.doubleValue(), n2.doubleValue() ); - return arithmetic(luan,"__pow",o1,o2); - } -}
--- a/src/luan/impl/RepeatStmt.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class RepeatStmt extends CodeImpl implements Stmt { - private final Stmt doStmt; - private final Expr cnd; - - RepeatStmt(LuanSource.Element se,Stmt doStmt,Expr cnd) { - super(se); - this.doStmt = doStmt; - this.cnd = cnd; - } - - @Override public void eval(LuanStateImpl luan) throws LuanException { - try { - do { - doStmt.eval(luan); - } while( !luan.bit(se).checkBoolean( cnd.eval(luan) ) ); - } catch(BreakException e) {} - } -}
--- a/src/luan/impl/ReturnException.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -package luan.impl; - - -final class ReturnException extends RuntimeException {}
--- a/src/luan/impl/ReturnStmt.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanFunction; -import luan.LuanSource; - - -final class ReturnStmt extends CodeImpl implements Stmt { - private final Expressions expressions; - private final Expr tailFnExpr; - boolean throwReturnException = true; - - ReturnStmt(LuanSource.Element se,Expressions expressions) { - super(se); - if( expressions instanceof FnCall ) { // tail call - FnCall fnCall = (FnCall)expressions; - this.expressions = fnCall.args; - this.tailFnExpr = fnCall.fnExpr; - } else { - this.expressions = expressions; - this.tailFnExpr = null; - } - } - - @Override public void eval(LuanStateImpl luan) throws LuanException { - luan.returnValues = expressions.eval(luan); - if( tailFnExpr != null ) { - LuanFunction tailFn = luan.bit(se).checkFunction( tailFnExpr.eval(luan) ); - if( tailFn instanceof Closure ) { - luan.tailFn = (Closure)tailFn; - } else { - luan.returnValues = luan.bit(tailFnExpr.se()).call(tailFn,tailFnExpr.se().text(),Luan.array(luan.returnValues)); - } - } - if( throwReturnException ) - throw new ReturnException(); - } -}
--- a/src/luan/impl/SetLocalVar.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -package luan.impl; - - -final class SetLocalVar implements Settable { - private final int index; - - SetLocalVar(int index) { - this.index = index; - } - - @Override public void set(LuanStateImpl luan,Object value) { - luan.stackSet( index, value ); - } -}
--- a/src/luan/impl/SetStmt.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; - - -final class SetStmt implements Stmt { - private final Settable[] vars; - private final Expressions expressions; - - SetStmt(Settable var,Expr expr) { - this( new Settable[]{var}, expr ); - } - - SetStmt(Settable[] vars,Expressions expressions) { - this.vars = vars; - this.expressions = expressions; - } - - @Override public void eval(LuanStateImpl luan) throws LuanException { - final Object obj = expressions.eval(luan); - if( obj instanceof Object[] ) { - Object[] vals = (Object[])obj; - for( int i=0; i<vars.length; i++ ) { - Object val = i < vals.length ? vals[i] : null; - vars[i].set(luan,val); - } - } else { - vars[0].set(luan,obj); - for( int i=1; i<vars.length; i++ ) { - vars[i].set(luan,null); - } - } - } - -}
--- a/src/luan/impl/SetTableEntry.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -package luan.impl; - -import luan.LuanException; -import luan.LuanTable; -import luan.Luan; -import luan.LuanFunction; -import luan.LuanSource; - - -final class SetTableEntry extends CodeImpl implements Settable { - private final Expr tableExpr; - private final Expr keyExpr; - - SetTableEntry(LuanSource.Element se,Expr tableExpr,Expr keyExpr) { - super(se); - this.tableExpr = tableExpr; - this.keyExpr = keyExpr; - } - - @Override public void set(LuanStateImpl luan,Object value) throws LuanException { - newindex( luan, tableExpr.eval(luan), keyExpr.eval(luan), value ); - } - - private void newindex(LuanStateImpl luan,Object t,Object key,Object value) throws LuanException { - Object h; - if( t instanceof LuanTable ) { - LuanTable table = (LuanTable)t; - Object old = table.put(key,value); - if( old != null ) - return; - h = luan.getHandler("__newindex",t); - if( h==null ) - return; - table.put(key,old); - } else { - h = luan.getHandler("__newindex",t); - if( h==null ) - throw luan.bit(se).exception( "attempt to index a " + Luan.type(t) + " value" ); - } - if( h instanceof LuanFunction ) { - LuanFunction fn = (LuanFunction)h; - luan.bit(se).call(fn,"__newindex",new Object[]{t,key,value}); - return; - } - newindex(luan,h,key,value); - } - -}
--- a/src/luan/impl/SetUpVar.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -package luan.impl; - - -final class SetUpVar implements Settable { - private final int index; - - SetUpVar(int index) { - this.index = index; - } - - @Override public void set(LuanStateImpl luan,Object value) { - luan.closure().upValues()[index].set(value); - } -}
--- a/src/luan/impl/Settable.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -package luan.impl; - -import luan.LuanException; - - -interface Settable { - public void set(LuanStateImpl luan,Object value) throws LuanException; -}
--- a/src/luan/impl/Stmt.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -package luan.impl; - -import luan.LuanException; - - -interface Stmt { - public void eval(LuanStateImpl luan) throws LuanException; - - static final Stmt EMPTY = new Stmt() { - @Override public void eval(LuanStateImpl luan) {} - }; -}
--- a/src/luan/impl/SubExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class SubExpr extends BinaryOpExpr { - - SubExpr(LuanSource.Element se,Expr op1,Expr op2) { - super(se,op1,op2); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object o1 = op1.eval(luan); - Object o2 = op2.eval(luan); - Number n1 = Luan.toNumber(o1); - Number n2 = Luan.toNumber(o2); - if( n1 != null && n2 != null ) - return n1.doubleValue() - n2.doubleValue(); - return arithmetic(luan,"__sub",o1,o2); - } -}
--- a/src/luan/impl/TableExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -package luan.impl; - -import luan.LuanException; -import luan.LuanTable; -import luan.LuanSource; - - -final class TableExpr extends CodeImpl implements Expr { - - static class Field { - final Expr key; - final Expr value; - - Field(Expr key,Expr value) { - this.key = key; - this.value = value; - } - } - - private final Field[] fields; - private final Expressions expressions; - - TableExpr(LuanSource.Element se,Field[] fields,Expressions expressions) { - super(se); - this.fields = fields; - this.expressions = expressions; - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - LuanTable table = new LuanTable(); - for( Field field : fields ) { - table.put( field.key.eval(luan), field.value.eval(luan) ); - } - Object obj = expressions.eval(luan); - if( obj instanceof Object[] ) { - Object[] a = (Object[])obj; - for( int i=0; i<a.length; i++ ) { - table.put( i+1, a[i] ); - } - } else { - table.put( 1, obj ); - } - return table; - } -}
--- a/src/luan/impl/TryStmt.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; - - -final class TryStmt implements Stmt { - private final Stmt tryBlock; - private final int iExceptionVar; - private final Stmt catchBlock; - - TryStmt(Stmt tryBlock,int iExceptionVar,Stmt catchBlock) { - this.tryBlock = tryBlock; - this.iExceptionVar = iExceptionVar; - this.catchBlock = catchBlock; - } - - @Override public void eval(LuanStateImpl luan) throws LuanException { - try { - tryBlock.eval(luan); - } catch(LuanException e) { - try { - luan.stackSet( iExceptionVar, e ); - catchBlock.eval(luan); - } finally { - luan.stackClear(iExceptionVar,iExceptionVar+1); - } - } - } -}
--- a/src/luan/impl/UnaryOpExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -package luan.impl; - -import luan.LuanSource; - - -abstract class UnaryOpExpr extends CodeImpl implements Expr { - final Expr op; - - UnaryOpExpr(LuanSource.Element se,Expr op) { - super(se); - this.op = op; - } -}
--- a/src/luan/impl/UnmExpr.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanFunction; -import luan.LuanException; -import luan.LuanSource; -import luan.LuanBit; - - -// unary minus -final class UnmExpr extends UnaryOpExpr { - - UnmExpr(LuanSource.Element se,Expr op) { - super(se,op); - } - - @Override public Object eval(LuanStateImpl luan) throws LuanException { - Object o = op.eval(luan); - Number n = Luan.toNumber(o); - if( n != null ) - return -n.doubleValue(); - LuanBit bit = luan.bit(se); - LuanFunction fn = bit.getHandlerFunction("__unm",o); - if( fn != null ) { - return Luan.first(bit.call(fn,"__unm",new Object[]{o})); - } - throw bit.exception("attempt to perform arithmetic on a "+Luan.type(o)+" value"); - } -}
--- a/src/luan/impl/UpValue.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -package luan.impl; - -import luan.DeepCloner; -import luan.DeepCloneable; -import luan.LuanException; - - -final class UpValue implements DeepCloneable<UpValue> { - private Object[] stack; - private int index; - private boolean isClosed = false; - private Object value; - - UpValue(Object[] stack,int index) { - this.stack = stack; - this.index = index; - } - - UpValue(Object value) { - this.value = value; - this.isClosed = true; - } - - private UpValue() {} - - @Override public UpValue shallowClone() { - return new UpValue(); - } - - @Override public void deepenClone(UpValue clone,DeepCloner cloner) { - clone.isClosed = isClosed; - if( isClosed ) { - clone.value = cloner.get(value); - } else { - clone.stack = cloner.deepClone(stack); - clone.index = index; - } - } - - Object get() { - return isClosed ? value : stack[index]; - } - - void set(Object value) { - if( isClosed ) { - this.value = value; - } else { - stack[index] = value; - } - } - - void close() { - value = stack[index]; - isClosed = true; - stack = null; - } - - static interface Getter { - public UpValue get(LuanStateImpl luan) throws LuanException; - } - - static final class StackGetter implements Getter { - private final int index; - - StackGetter(int index) { - this.index = index; - } - - public UpValue get(LuanStateImpl luan) { - return luan.getUpValue(index); - } - } - - static final class NestedGetter implements Getter { - private final int index; - - NestedGetter(int index) { - this.index = index; - } - - public UpValue get(LuanStateImpl luan) { - return luan.closure().upValues()[index]; - } - } - - static final class EnvGetter implements Getter { - - public UpValue get(LuanStateImpl luan) throws LuanException { - return luan.getUpValue(this); - } - } - - static final class ValueGetter implements Getter { - private final UpValue upValue; - - ValueGetter(Object value) { - this.upValue = new UpValue(value); - } - - public UpValue get(LuanStateImpl luan) { - return upValue; - } - } - -}
--- a/src/luan/impl/VarArgs.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -package luan.impl; - -import luan.LuanSource; - - -final class VarArgs extends CodeImpl implements Expressions { - - VarArgs(LuanSource.Element se) { - super(se); - } - - @Override public Object[] eval(LuanStateImpl luan) { - return luan.varArgs(); - } -}
--- a/src/luan/impl/WhileStmt.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -package luan.impl; - -import luan.Luan; -import luan.LuanException; -import luan.LuanSource; - - -final class WhileStmt extends CodeImpl implements Stmt { - private final Expr cnd; - private final Stmt doStmt; - - WhileStmt(LuanSource.Element se,Expr cnd,Stmt doStmt) { - super(se); - this.cnd = cnd; - this.doStmt = doStmt; - } - - @Override public void eval(LuanStateImpl luan) throws LuanException { - try { - while( luan.bit(se).checkBoolean( cnd.eval(luan) ) ) { - doStmt.eval(luan); - } - } catch(BreakException e) {} - } -}
--- a/src/luan/init.luan Sun Jun 22 05:20:30 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")
--- a/src/luan/modules/BasicLuan.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ -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 BasicLuan { - - 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(BasicLuan.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(BasicLuan.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)) : IoLuan.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/modules/BinaryLuan.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -package luan.modules; - -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanException; - - -public final class BinaryLuan { - - 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(BinaryLuan.class.getMethod(method,parameterTypes),null) ); - } - - public static String to_string(byte[] bytes) { - return new String(bytes); - } - -}
--- a/src/luan/modules/HtmlLuan.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -package luan.modules; - -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanException; - - -public final class HtmlLuan { - - 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(HtmlLuan.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/modules/IoLuan.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,504 +0,0 @@ -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 IoLuan { - - 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( - IoLuan.class.getMethod( "stdin_read_text" ), null - ) ); - stdin.put( "read_binary", new LuanJavaFunction( - IoLuan.class.getMethod( "stdin_read_binary" ), null - ) ); - stdin.put( "read_lines", new LuanJavaFunction( - IoLuan.class.getMethod( "stdin_read_lines" ), null - ) ); - stdin.put( "read_blocks", new LuanJavaFunction( - IoLuan.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(IoLuan.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 IoLuan() {} // never -}
--- a/src/luan/modules/JavaLuan.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,450 +0,0 @@ -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 JavaLuan { - - 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(JavaLuan.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 = JavaLuan.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(JavaLuan.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/modules/MathLuan.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -package luan.modules; - -import luan.LuanState; -import luan.LuanTable; -import luan.LuanFunction; -import luan.LuanJavaFunction; -import luan.LuanException; - - -public final class MathLuan { - - 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(MathLuan.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/modules/PackageLuan.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,170 +0,0 @@ -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 PackageLuan { - - private static final String jpath = "luan.modules.?Luan.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(PackageLuan.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 = BasicLuan.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/modules/PickleClient.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -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(); - } - - -}
--- a/src/luan/modules/PickleCon.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -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 = BasicLuan.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/modules/PickleServer.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -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; - } - -}
--- a/src/luan/modules/Reactionary.luan Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ --- Reactionary - -host = "localhost" -port = 9101 - -function put_site(domain,password,dir) - local pc = Io.Socket(host,port).Pickle_client() - local pickle = pc.pickle - pc.call %> - Reactionary.do_put_site(<%=pickle(domain)%>,<%=pickle(password)%>,<%=pickle(dir)%>) - <% - pc.close() -end - -function delete_site(domain,password) - local pc = Io.Socket(host,port).Pickle_client() - local pickle = pc.pickle - pc.call %> - Reactionary.do_delete_site(<%=pickle(domain)%>,<%=pickle(password)%>) - <% - pc.close() -end
--- a/src/luan/modules/StringLuan.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -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); - } - -}
--- a/src/luan/modules/TableLuan.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -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 TableLuan { - - 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(TableLuan.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/modules/ThreadLuan.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -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 ThreadLuan { - - 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(ThreadLuan.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/modules/Utils.java Sun Jun 22 05:20:30 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -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; - } -}