Mercurial Hosting > luan
changeset 86:6db8f286fa6c
_ENV is per module, not global
git-svn-id: https://luan-java.googlecode.com/svn/trunk@87 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Wed, 27 Feb 2013 08:03:51 +0000 |
parents | b2551f00bc51 |
children | eaf37cfa30c2 |
files | src/luan/LuanFunction.java src/luan/LuanJavaFunction.java src/luan/LuanLoader.java src/luan/LuanState.java src/luan/LuanTable.java src/luan/interp/Chunk.java src/luan/interp/Closure.java src/luan/interp/FnDef.java src/luan/interp/LuanCompiler.java src/luan/interp/LuanParser.java src/luan/interp/LuanStateImpl.java src/luan/interp/UpValue.java src/luan/lib/BasicLib.java src/luan/lib/HtmlLib.java src/luan/lib/HttpLib.java src/luan/lib/JavaLib.java src/luan/lib/MathLib.java src/luan/lib/PackageLib.java src/luan/lib/StringLib.java src/luan/lib/TableLib.java src/luan/lib/Utils.java src/luan/tools/CmdLine.java src/luan/tools/WebRun.java src/luan/tools/WebServlet.java src/luan/tools/WebShell.java |
diffstat | 25 files changed, 342 insertions(+), 241 deletions(-) [+] |
line wrap: on
line diff
--- a/src/luan/LuanFunction.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/LuanFunction.java Wed Feb 27 08:03:51 2013 +0000 @@ -5,7 +5,7 @@ public abstract Object[] call(LuanState luan,Object[] args) throws LuanException; - public static final Object[] EMPTY_RTN = new Object[0]; + public static final Object[] EMPTY = new Object[0]; @Override public String toString() { return "function: " + Integer.toHexString(hashCode());
--- a/src/luan/LuanJavaFunction.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/LuanJavaFunction.java Wed Feb 27 08:03:51 2013 +0000 @@ -146,7 +146,7 @@ private static final RtnConverter RTN_EMPTY = new RtnConverter() { public Object[] convert(Object obj) { - return EMPTY_RTN; + return EMPTY; } }; @@ -331,6 +331,8 @@ 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;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/LuanLoader.java Wed Feb 27 08:03:51 2013 +0000 @@ -0,0 +1,12 @@ +package luan; + + +public abstract class LuanLoader extends LuanFunction { + + protected abstract void load(LuanState luan) throws LuanException; + + @Override public final Object[] call(LuanState luan,Object[] args) throws LuanException { + load(luan); + return EMPTY; + } +}
--- a/src/luan/LuanState.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/LuanState.java Wed Feb 27 08:03:51 2013 +0000 @@ -4,6 +4,8 @@ import java.io.PrintStream; import java.util.List; import java.util.ArrayList; +import java.util.Map; +import java.util.LinkedHashMap; import luan.interp.LuanCompiler; import luan.lib.BasicLib; import luan.lib.PackageLib; @@ -15,10 +17,11 @@ public abstract class LuanState implements DeepCloneable<LuanState> { + public static final String _G = "_G"; - private LuanTable global; private LuanTable loaded; private LuanTable preload; + private final List<String> defaultMods; public InputStream in = System.in; public PrintStream out = System.out; @@ -28,14 +31,15 @@ final List<StackTraceElement> stackTrace = new ArrayList<StackTraceElement>(); protected LuanState() { - global = new LuanTable(); loaded = new LuanTable(); preload = new LuanTable(); + defaultMods = new ArrayList<String>(); mtGetters = new ArrayList<MetatableGetter>(); } protected LuanState(LuanState luan) { mtGetters = new ArrayList<MetatableGetter>(luan.mtGetters); + defaultMods = new ArrayList<String>(luan.defaultMods); } public final LuanState deepClone() { @@ -43,14 +47,11 @@ } @Override public void deepenClone(LuanState clone,DeepCloner cloner) { - clone.global = cloner.deepClone(global); clone.loaded = cloner.deepClone(loaded); clone.preload = cloner.deepClone(preload); } - public final LuanTable global() { - return global; - } + public abstract LuanTable currentEnvironment(); public final LuanTable loaded() { return loaded; @@ -62,7 +63,7 @@ public final Object get(String name) { String[] a = name.split("\\."); - LuanTable t = global; + LuanTable t = loaded; for( int i=0; i<a.length-1; i++ ) { Object obj = t.get(a[i]); if( !(obj instanceof LuanTable) ) @@ -74,7 +75,7 @@ public final Object set(String name,Object value) { String[] a = name.split("\\."); - LuanTable t = global; + LuanTable t = loaded; for( int i=0; i<a.length-1; i++ ) { Object obj = t.get(a[i]); if( !(obj instanceof LuanTable) ) @@ -85,12 +86,24 @@ } public final void load(String modName,LuanFunction loader) throws LuanException { - Object mod = Luan.first(call(loader,LuanElement.JAVA,"loader",modName)); - if( mod == null ) - mod = true; - loaded.put(modName,mod); - if( mod instanceof LuanTable ) - global.put(modName,mod); + preload.put(modName,loader); + defaultMods.add(modName); + PackageLib.require(this,modName); + } + + public final LuanTable newEnvironment() throws LuanException { + LuanTable env = new LuanTable(); + for( String modName : defaultMods ) { + PackageLib.require(this,modName,env); + LuanTable mod = (LuanTable)loaded.get(modName); + LuanTable global = (LuanTable)mod.get(_G); + if( global != null ) { + for( Map.Entry<Object,Object> entry : global ) { + env.put( entry.getKey(), entry.getValue() ); + } + } + } + return env; } public static LuanState newStandard() { @@ -109,8 +122,8 @@ } } - public final Object[] eval(String cmd,String sourceName) throws LuanException { - LuanFunction fn = BasicLib.load(this,cmd,sourceName); + public final Object[] eval(String cmd,String sourceName,LuanTable env) throws LuanException { + LuanFunction fn = BasicLib.load(this,cmd,sourceName,env); return call(fn,null,null); }
--- a/src/luan/LuanTable.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/LuanTable.java Wed Feb 27 08:03:51 2013 +0000 @@ -13,7 +13,7 @@ import java.util.IdentityHashMap; -public final class LuanTable implements DeepCloneable<LuanTable> { +public final class LuanTable implements DeepCloneable<LuanTable>, Iterable<Map.Entry<Object,Object>> { private Map<Object,Object> map = null; private List<Object> list = null; private LuanTable metatable = null;
--- a/src/luan/interp/Chunk.java Mon Feb 25 03:53:54 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -package luan.interp; - -import luan.LuanException; -import luan.LuanSource; - - -final class Chunk extends CodeImpl implements Expr { - final Stmt block; - final int stackSize; - final int numArgs; - final boolean isVarArg; - final UpValue.Getter[] upValueGetters; - - Chunk(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) { - return new Closure(luan,this); - } - -}
--- a/src/luan/interp/Closure.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/interp/Closure.java Wed Feb 27 08:03:51 2013 +0000 @@ -9,25 +9,20 @@ final class Closure extends LuanFunction implements DeepCloneable<Closure> { - private final Chunk chunk; + private final FnDef fnDef; private UpValue[] upValues; - private final static UpValue[] NO_UP_VALUES = new UpValue[0]; - Closure(LuanStateImpl luan,Chunk chunk) { - this.chunk = chunk; - UpValue.Getter[] upValueGetters = chunk.upValueGetters; - if( upValueGetters.length==0 ) { - upValues = NO_UP_VALUES; - } else { - upValues = new UpValue[upValueGetters.length]; - for( int i=0; i<upValues.length; i++ ) { - upValues[i] = upValueGetters[i].get(luan); - } + 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.chunk = c.chunk; + this.fnDef = c.fnDef; } @Override public Closure shallowClone() { @@ -48,27 +43,27 @@ private static Object[] call(Closure closure,LuanStateImpl luan,Object[] args) throws LuanException { while(true) { - Chunk chunk = closure.chunk; + FnDef fnDef = closure.fnDef; Object[] varArgs = null; - if( chunk.isVarArg ) { - if( args.length > chunk.numArgs ) { - varArgs = new Object[ args.length - chunk.numArgs ]; + 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[chunk.numArgs+i]; + varArgs[i] = args[fnDef.numArgs+i]; } } else { - varArgs = LuanFunction.EMPTY_RTN; + varArgs = LuanFunction.EMPTY; } } - Object[] stack = luan.newFrame(closure,chunk.stackSize,varArgs); - final int n = Math.min(args.length,chunk.numArgs); + 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; Closure tailFn; try { - chunk.block.eval(luan); + fnDef.block.eval(luan); } catch(ReturnException e) { } finally { returnValues = luan.returnValues;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/interp/FnDef.java Wed Feb 27 08:03:51 2013 +0000 @@ -0,0 +1,42 @@ +package luan.interp; + +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/interp/LuanCompiler.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/interp/LuanCompiler.java Wed Feb 27 08:03:51 2013 +0000 @@ -10,20 +10,21 @@ import luan.LuanException; import luan.LuanSource; import luan.LuanElement; +import luan.LuanTable; public final class LuanCompiler { private LuanCompiler() {} // never - public static LuanFunction compile(LuanState luan,LuanSource src) throws LuanException { - LuanParser parser = Parboiled.createParser(LuanParser.class); - parser.source = src; + public static LuanFunction compile(LuanState luan,LuanSource src,LuanTable env) throws LuanException { + UpValue.Getter envGetter = env!=null ? new UpValue.ValueGetter(env) : new UpValue.EnvGetter(); + LuanParser parser = Parboiled.createParser(LuanParser.class,src,envGetter); ParsingResult<?> result = new ReportingParseRunner(parser.Target()).run(src.text); // ParsingResult<?> result = new TracingParseRunner(parser.Target()).run(src); if( result.hasErrors() ) throw new LuanException( luan, LuanElement.COMPILER, ErrorUtils.printParseErrors(result) ); - Chunk chunk = (Chunk)result.resultValue; - return new Closure((LuanStateImpl)luan,chunk); + FnDef fnDef = (FnDef)result.resultValue; + return new Closure((LuanStateImpl)luan,fnDef); } public static LuanState newLuanState() {
--- a/src/luan/interp/LuanParser.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/interp/LuanParser.java Wed Feb 27 08:03:51 2013 +0000 @@ -24,14 +24,6 @@ class LuanParser extends BaseParser<Object> { - LuanSource source; - - LuanSource.Element se(int start) { - return new LuanSource.Element(source,start,currentIndex()); - } - - static final String _ENV = "_ENV"; - static final class Frame { final Frame parent; final List<String> symbols = new ArrayList<String>(); @@ -41,14 +33,16 @@ final List<String> upValueSymbols = new ArrayList<String>(); final List<UpValue.Getter> upValueGetters = new ArrayList<UpValue.Getter>(); - Frame() { + Frame(UpValue.Getter envGetter) { this.parent = null; upValueSymbols.add(_ENV); - upValueGetters.add(UpValue.globalGetter); + upValueGetters.add(envGetter); } Frame(Frame parent) { this.parent = parent; + if( upValueIndex(_ENV) != 0 ) + throw new RuntimeException(); } int stackIndex(String name) { @@ -82,10 +76,22 @@ } } + static final String _ENV = "_ENV"; static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0]; +// UpValue.Getter envGetter = new UpValue.EnvGetter(); + final LuanSource source; + Frame frame; int nEquals; - Frame frame = new Frame(); + + LuanParser(LuanSource source,UpValue.Getter envGetter) { + this.source = source; + this.frame = new Frame(envGetter); + } + + LuanSource.Element se(int start) { + return new LuanSource.Element(source,start,currentIndex()); + } boolean nEquals(int n) { nEquals = n; @@ -140,8 +146,8 @@ return true; } - Chunk newChunk(int start) { - return new Chunk( se(start), (Stmt)pop(), frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) ); + FnDef newFnDef(int start) { + return new FnDef( se(start), (Stmt)pop(), frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) ); } Rule Target() { @@ -153,13 +159,13 @@ Sequence( ExpList(false), push( new ReturnStmt( se(start.get()), (Expressions)pop() ) ), - push( newChunk(start.get()) ), + push( newFnDef(start.get()) ), EOI ), Sequence( action( frame.isVarArg = true ), Block(), - push( newChunk(start.get()) ), + push( newFnDef(start.get()) ), EOI ) ) @@ -648,7 +654,7 @@ ) ), ')', Spaces(inParens), Block(), Keyword("end",inParens), - push( newChunk(start.get()) ), + push( newFnDef(start.get()) ), action( frame = frame.parent ) ); }
--- a/src/luan/interp/LuanStateImpl.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/interp/LuanStateImpl.java Wed Feb 27 08:03:51 2013 +0000 @@ -2,6 +2,8 @@ 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; @@ -53,10 +55,11 @@ } private Frame frame = null; - Object[] returnValues = LuanFunction.EMPTY_RTN; + Object[] returnValues = LuanFunction.EMPTY; Closure tailFn; + Map<UpValue.EnvGetter,UpValue> envs = new HashMap<UpValue.EnvGetter,UpValue>(); - public LuanStateImpl() {} + LuanStateImpl() {} private LuanStateImpl(LuanStateImpl luan) { super(luan); @@ -68,6 +71,15 @@ 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) { frame = new Frame(frame,closure,stackSize,varArgs); @@ -75,7 +87,7 @@ } void popFrame() { - returnValues = LuanFunction.EMPTY_RTN; + returnValues = LuanFunction.EMPTY; tailFn = null; frame = frame.previousFrame; } @@ -104,6 +116,22 @@ return frame.getUpValue(index); } + UpValue getUpValue(UpValue.EnvGetter getter) throws LuanException { + UpValue uv = envs.get(getter); + if( uv == null ) { + LuanTable env = newEnvironment(); + 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(); + } + final Object arithmetic(LuanElement el,String op,Object o1,Object o2) throws LuanException { LuanFunction fn = getBinHandler(el,op,o1,o2);
--- a/src/luan/interp/UpValue.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/interp/UpValue.java Wed Feb 27 08:03:51 2013 +0000 @@ -2,6 +2,7 @@ import luan.DeepCloner; import luan.DeepCloneable; +import luan.LuanException; final class UpValue implements DeepCloneable<UpValue> { @@ -55,7 +56,7 @@ } static interface Getter { - public UpValue get(LuanStateImpl luan); + public UpValue get(LuanStateImpl luan) throws LuanException; } static final class StackGetter implements Getter { @@ -82,10 +83,23 @@ } } - static final Getter globalGetter = new Getter() { + 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 new UpValue(luan.global()); + return upValue; } - }; + } }
--- a/src/luan/lib/BasicLib.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/lib/BasicLib.java Wed Feb 27 08:03:51 2013 +0000 @@ -10,6 +10,7 @@ import luan.LuanState; import luan.LuanTable; import luan.LuanFunction; +import luan.LuanLoader; import luan.LuanJavaFunction; import luan.LuanException; import luan.LuanSource; @@ -21,10 +22,11 @@ public static final String NAME = "basic"; - public static final LuanFunction LOADER = new LuanFunction() { - public Object[] call(LuanState luan,Object[] args) throws LuanException { - LuanTable global = luan.global(); - global.put( "_G", global ); + public static final LuanLoader LOADER = new LuanLoader() { + @Override protected void load(LuanState luan) { + LuanTable module = new LuanTable(); + LuanTable global = new LuanTable(); + module.put( LuanState._G, global ); try { global.put( "assert", new LuanJavaFunction(BasicLib.class.getMethod("assert_",LuanState.class,Object.class,String.class),null) ); add( global, "assert_boolean", LuanState.class, Boolean.TYPE ); @@ -32,13 +34,13 @@ add( global, "assert_number", LuanState.class, Number.class ); add( global, "assert_string", LuanState.class, String.class ); add( global, "assert_table", LuanState.class, LuanTable.class ); - add( global, "do_file", LuanState.class, String.class ); + add( global, "do_file", LuanState.class, String.class, LuanTable.class ); add( global, "error", LuanState.class, Object.class ); add( global, "get_metatable", LuanState.class, Object.class ); - add( global, "ipairs", LuanTable.class ); - add( global, "load", LuanState.class, String.class, String.class ); - add( global, "load_file", LuanState.class, String.class ); - add( global, "pairs", LuanTable.class ); + add( global, "ipairs", LuanState.class, LuanTable.class ); + add( global, "load", LuanState.class, String.class, String.class, LuanTable.class ); + add( global, "load_file", LuanState.class, String.class, LuanTable.class ); + add( global, "pairs", LuanState.class, LuanTable.class ); add( global, "print", LuanState.class, new Object[0].getClass() ); add( global, "raw_equal", Object.class, Object.class ); add( global, "raw_get", LuanTable.class, Object.class ); @@ -49,12 +51,10 @@ add( global, "to_string", LuanState.class, Object.class ); add( global, "type", Object.class ); global.put( "_VERSION", Luan.version ); - - add( global, "make_standard", LuanState.class ); } catch(NoSuchMethodException e) { throw new RuntimeException(e); } - return LuanFunction.EMPTY_RTN; + luan.loaded().put(NAME,module); } }; @@ -62,20 +62,6 @@ t.put( method, new LuanJavaFunction(BasicLib.class.getMethod(method,parameterTypes),null) ); } - public static void make_standard(LuanState luan) { - LuanTable global = luan.global(); - global.put( "dofile", global.get("do_file") ); - global.put( "getmetatable", global.get("get_metatable") ); - global.put( "loadfile", global.get("load_file") ); - global.put( "rawequal", global.get("raw_equal") ); - global.put( "rawget", global.get("raw_get") ); - global.put( "rawlen", global.get("raw_len") ); - global.put( "rawset", global.get("raw_set") ); - global.put( "setmetatable", global.get("set_metatable") ); - global.put( "tonumber", global.get("to_number") ); - global.put( "tostring", global.get("to_string") ); - } - public static void print(LuanState luan,Object... args) throws LuanException { for( int i=0; i<args.length; i++ ) { if( i > 0 ) @@ -89,22 +75,22 @@ return Luan.type(obj); } - public static LuanFunction load(LuanState luan,String text,String sourceName) throws LuanException { - return LuanCompiler.compile(luan,new LuanSource(sourceName,text)); + public static LuanFunction load(LuanState luan,String text,String sourceName,LuanTable env) throws LuanException { + return LuanCompiler.compile(luan,new LuanSource(sourceName,text),env); } - public static LuanFunction load_file(LuanState luan,String fileName) throws LuanException { + public static LuanFunction load_file(LuanState luan,String fileName,LuanTable env) throws LuanException { try { String src = fileName==null ? Utils.readAll(new InputStreamReader(System.in)) : Utils.read(new File(fileName)); - return load(luan,src,fileName); + return load(luan,src,fileName,env); } catch(IOException e) { throw new LuanException(luan,LuanElement.JAVA,e); } } - public static Object[] do_file(LuanState luan,String fileName) throws LuanException { - LuanFunction fn = load_file(luan,fileName); + public static Object[] do_file(LuanState luan,String fileName,LuanTable env) throws LuanException { + LuanFunction fn = load_file(luan,fileName,env); return luan.call(fn,LuanElement.JAVA,null); } @@ -112,18 +98,20 @@ return new LuanFunction() { public Object[] call(LuanState luan,Object[] args) { if( !iter.hasNext() ) - return LuanFunction.EMPTY_RTN; + return LuanFunction.EMPTY; Map.Entry<Object,Object> entry = iter.next(); return new Object[]{entry.getKey(),entry.getValue()}; } }; } - public static LuanFunction pairs(LuanTable t) { + public static LuanFunction pairs(LuanState luan,LuanTable t) throws LuanException { + Utils.checkNotNull(luan,t,"table"); return pairs( t.iterator() ); } - public static LuanFunction ipairs(LuanTable t) { + public static LuanFunction ipairs(LuanState luan,LuanTable t) throws LuanException { + Utils.checkNotNull(luan,t,"table"); return pairs( t.listIterator() ); } @@ -181,23 +169,18 @@ throw new LuanException( luan, LuanElement.JAVA, msg ); } - private static void checkNotNull(LuanState luan,Object v,String expected) throws LuanException { - if( v == null ) - throw new LuanException(luan,LuanElement.JAVA,"bad argument #1 ("+expected+" expected, got nil)"); - } - public static String assert_string(LuanState luan,String v) throws LuanException { - checkNotNull(luan,v,"string"); + Utils.checkNotNull(luan,v,"string"); return v; } public static Number assert_number(LuanState luan,Number v) throws LuanException { - checkNotNull(luan,v,"number"); + Utils.checkNotNull(luan,v,"number"); return v; } public static LuanTable assert_table(LuanState luan,LuanTable v) throws LuanException { - checkNotNull(luan,v,"table"); + Utils.checkNotNull(luan,v,"table"); return v; }
--- a/src/luan/lib/HtmlLib.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/lib/HtmlLib.java Wed Feb 27 08:03:51 2013 +0000 @@ -3,6 +3,7 @@ import luan.LuanState; import luan.LuanTable; import luan.LuanFunction; +import luan.LuanLoader; import luan.LuanJavaFunction; @@ -10,16 +11,15 @@ public static final String NAME = "html"; - public static final LuanFunction LOADER = new LuanFunction() { - public Object[] call(LuanState luan,Object[] args) { + public static final LuanLoader LOADER = new LuanLoader() { + @Override protected void load(LuanState luan) { LuanTable module = new LuanTable(); - LuanTable global = luan.global(); try { add( module, "encode", String.class ); } catch(NoSuchMethodException e) { throw new RuntimeException(e); } - return new Object[]{module}; + luan.loaded().put(NAME,module); } };
--- a/src/luan/lib/HttpLib.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/lib/HttpLib.java Wed Feb 27 08:03:51 2013 +0000 @@ -18,17 +18,23 @@ public final class HttpLib { public static final String NAME = "http"; - public static final String FN_NAME = "serve_http"; + public static final String FN_NAME = "http.server"; + + public static void load(LuanState luan) throws LuanException { + PackageLib.require(luan,NAME); + Object fn = luan.get(HttpLib.FN_NAME); + if( !(fn instanceof LuanFunction) ) + throw new LuanException( luan, LuanElement.JAVA, "function '"+HttpLib.FN_NAME+"' not defined" ); + } public static void service(LuanState luan,HttpServletRequest request,HttpServletResponse response) throws LuanException, IOException { - LuanFunction fn = (LuanFunction)luan.global().get(FN_NAME); + LuanFunction fn = (LuanFunction)luan.get(FN_NAME); ServletOutputStream sout = response.getOutputStream(); luan.out = new PrintStream(sout); - LuanTable module = new LuanTable(); - luan.global().put(NAME,module); + LuanTable module = (LuanTable)luan.loaded().get(NAME); LuanTable parameters = new LuanTable(); LuanTable parameter_lists = new LuanTable();
--- a/src/luan/lib/JavaLib.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/lib/JavaLib.java Wed Feb 27 08:03:51 2013 +0000 @@ -21,6 +21,7 @@ import luan.MetatableGetter; import luan.LuanException; import luan.LuanFunction; +import luan.LuanLoader; import luan.LuanJavaFunction; import luan.LuanElement; @@ -29,11 +30,12 @@ public static final String NAME = "java"; - public static final LuanFunction LOADER = new LuanFunction() { - public Object[] call(LuanState luan,Object[] args) throws LuanException { + public static final LuanLoader LOADER = new LuanLoader() { + @Override protected void load(LuanState luan) { luan.addMetatableGetter(mg); LuanTable module = new LuanTable(); - LuanTable global = luan.global(); + LuanTable global = new LuanTable(); + module.put( LuanState._G, global ); try { global.put( "import", new LuanJavaFunction(JavaLib.class.getMethod("importClass",LuanState.class,String.class),null) ); module.put( "class", new LuanJavaFunction(JavaLib.class.getMethod("getClass",LuanState.class,String.class),null) ); @@ -41,7 +43,7 @@ } catch(NoSuchMethodException e) { throw new RuntimeException(e); } - return new Object[]{module}; + luan.loaded().put(NAME,module); } }; @@ -298,7 +300,7 @@ } public static void importClass(LuanState luan,String name) throws LuanException { - luan.global().put( name.substring(name.lastIndexOf('.')+1), getClass(luan,name) ); + luan.currentEnvironment().put( name.substring(name.lastIndexOf('.')+1), getClass(luan,name) ); } static class AmbiguousJavaFunction extends LuanFunction {
--- a/src/luan/lib/MathLib.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/lib/MathLib.java Wed Feb 27 08:03:51 2013 +0000 @@ -3,6 +3,7 @@ import luan.LuanState; import luan.LuanTable; import luan.LuanFunction; +import luan.LuanLoader; import luan.LuanJavaFunction; @@ -10,16 +11,15 @@ public static final String NAME = "math"; - public static final LuanFunction LOADER = new LuanFunction() { - public Object[] call(LuanState luan,Object[] args) { + public static final LuanLoader LOADER = new LuanLoader() { + @Override protected void load(LuanState luan) { LuanTable module = new LuanTable(); - LuanTable global = luan.global(); try { add( module, "floor", Double.TYPE ); } catch(NoSuchMethodException e) { throw new RuntimeException(e); } - return new Object[]{module}; + luan.loaded().put(NAME,module); } };
--- a/src/luan/lib/PackageLib.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/lib/PackageLib.java Wed Feb 27 08:03:51 2013 +0000 @@ -4,10 +4,12 @@ import java.io.IOException; import java.net.URL; import java.util.Arrays; +import java.util.Collections; import luan.Luan; import luan.LuanState; import luan.LuanTable; import luan.LuanFunction; +import luan.LuanLoader; import luan.LuanJavaFunction; import luan.LuanElement; import luan.LuanException; @@ -17,22 +19,23 @@ public static final String NAME = "package"; - public static final LuanFunction LOADER = new LuanFunction() { - public Object[] call(LuanState luan,Object[] args) throws LuanException { - LuanTable global = luan.global(); + public static final LuanLoader LOADER = new LuanLoader() { + @Override protected void load(LuanState luan) { LuanTable module = new LuanTable(); + LuanTable global = new LuanTable(); + module.put( LuanState._G, global ); module.put("loaded",luan.loaded()); module.put("preload",luan.preload()); -// module.put("path","?.lua"); + module.put("path","?.lua"); try { add( global, "require", LuanState.class, String.class ); - add( module, "module", LuanState.class, String.class ); + add( global, "module", LuanState.class, String.class ); add( module, "search_path", String.class, String.class ); } catch(NoSuchMethodException e) { throw new RuntimeException(e); } module.put("searchers",new LuanTable(Arrays.<Object>asList(preloadSearcher,fileSearcher,javaFileSearcher))); - return new Object[]{module}; + luan.loaded().put(NAME,module); } }; @@ -40,32 +43,39 @@ t.put( method, new LuanJavaFunction(PackageLib.class.getMethod(method,parameterTypes),null) ); } - public static void require(LuanState luan,String modName) throws LuanException { - Object mod = module(luan,modName); - if( mod instanceof LuanTable ) - luan.global().put(modName,mod); + public static void module(LuanState luan,String modName) throws LuanException { + LuanTable module = new LuanTable(); + luan.currentEnvironment().put(modName,module); + luan.loaded().put(modName,module); } - public static Object module(LuanState luan,String modName) throws LuanException { - Object mod = luan.loaded().get(modName); + public static void require(LuanState luan,String modName) throws LuanException { + require(luan,modName,luan.currentEnvironment()); + } + + public static void require(LuanState luan,String modName,LuanTable env) throws LuanException { + LuanTable mod = (LuanTable)luan.loaded().get(modName); if( mod == null ) { LuanTable searchers = (LuanTable)luan.get("package.searchers"); + if( searchers == null ) + searchers = new LuanTable(Collections.<Object>singletonList(preloadSearcher)); for( Object s : searchers.asList() ) { LuanFunction searcher = (LuanFunction)s; - Object[] a = luan.call(searcher,LuanElement.JAVA,"searcher",modName); + Object[] a = luan.call(searcher,LuanElement.JAVA,"<searcher>",modName); if( a.length >= 1 && a[0] instanceof LuanFunction ) { LuanFunction loader = (LuanFunction)a[0]; - Object extra = a.length >= 2 ? a[1] : null; - mod = Luan.first(luan.call(loader,LuanElement.JAVA,"loader",modName,extra)); - if( mod == null ) - mod = true; - luan.loaded().put(modName,mod); + luan.call(loader,LuanElement.JAVA,"<loader>"); + mod = (LuanTable)luan.loaded().get(modName); + if( mod==null ) + throw new LuanException( luan, LuanElement.JAVA, "module '"+modName+"' didn't define its module" ); + break; } } if( mod == null ) throw new LuanException( luan, LuanElement.JAVA, "module '"+modName+"' not found" ); } - return mod; + if( env != null ) + env.put(modName,mod); } public static String search_path(String name,String path) { @@ -77,12 +87,16 @@ return null; } - private static final LuanFunction fileLoader = new LuanFunction() { - public Object[] call(LuanState luan,Object[] args) throws LuanException { - String modName = (String)args[0]; - String fileName = (String)args[1]; - LuanFunction fn = BasicLib.load_file(luan,fileName); - return luan.call(fn,LuanElement.JAVA,modName,args); + private static final class FileLoader extends LuanLoader { + private final String fileName; + + FileLoader(String fileName) { + this.fileName = fileName; + } + + @Override protected void load(LuanState luan) throws LuanException { + LuanFunction fn = BasicLib.load_file(luan,fileName,null); + fn.call(luan,EMPTY); } }; @@ -91,9 +105,9 @@ String modName = (String)args[0]; String path = (String)luan.get("package.path"); if( path==null ) - return LuanFunction.EMPTY_RTN; + return LuanFunction.EMPTY; String file = search_path(modName,path); - return file==null ? LuanFunction.EMPTY_RTN : new Object[]{fileLoader,file}; + return file==null ? LuanFunction.EMPTY : new Object[]{new FileLoader(file)}; } }; @@ -108,14 +122,18 @@ - private static final LuanFunction javaFileLoader = new LuanFunction() { - public Object[] call(LuanState luan,Object[] args) throws LuanException { + private static final class JavaFileLoader extends LuanLoader { + private final URL url; + + JavaFileLoader(URL url) { + this.url = url; + } + + @Override protected void load(LuanState luan) throws LuanException { try { - String modName = (String)args[0]; - URL url = (URL)args[1]; String src = Utils.read(url); - LuanFunction fn = BasicLib.load(luan,src,url.toString()); - return luan.call(fn,LuanElement.JAVA,modName,args); + LuanFunction fn = BasicLib.load(luan,src,url.toString(),null); + fn.call(luan,EMPTY); } catch(IOException e) { throw new LuanException(luan,LuanElement.JAVA,e); } @@ -127,15 +145,15 @@ String modName = (String)args[0]; String path = (String)luan.get("package.jpath"); if( path==null ) - return LuanFunction.EMPTY_RTN; + return LuanFunction.EMPTY; for( String s : path.split(";") ) { String file = s.replaceAll("\\?",modName); URL url = ClassLoader.getSystemResource(file); if( url != null ) { - return new Object[]{javaFileLoader,url}; + return new Object[]{new JavaFileLoader(url)}; } } - return LuanFunction.EMPTY_RTN; + return LuanFunction.EMPTY; } };
--- a/src/luan/lib/StringLib.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/lib/StringLib.java Wed Feb 27 08:03:51 2013 +0000 @@ -6,6 +6,7 @@ import luan.LuanState; import luan.LuanTable; import luan.LuanFunction; +import luan.LuanLoader; import luan.LuanJavaFunction; import luan.LuanElement; import luan.LuanException; @@ -15,10 +16,9 @@ public static final String NAME = "string"; - public static final LuanFunction LOADER = new LuanFunction() { - public Object[] call(LuanState luan,Object[] args) throws LuanException { + public static final LuanLoader LOADER = new LuanLoader() { + @Override protected void load(LuanState luan) { LuanTable module = new LuanTable(); - LuanTable global = luan.global(); try { module.put( "byte", new LuanJavaFunction(StringLib.class.getMethod("byte_",String.class,Integer.class,Integer.class),null) ); module.put( "char", new LuanJavaFunction(StringLib.class.getMethod("char_",new byte[0].getClass()),null) ); @@ -36,7 +36,7 @@ } catch(NoSuchMethodException e) { throw new RuntimeException(e); } - return new Object[]{module}; + luan.loaded().put(NAME,module); } }; @@ -134,7 +134,7 @@ return new LuanFunction() { public Object[] call(LuanState luan,Object[] args) { if( !m.find() ) - return LuanFunction.EMPTY_RTN; + return LuanFunction.EMPTY; final int n = m.groupCount(); if( n == 0 ) return new String[]{m.group()};
--- a/src/luan/lib/TableLib.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/lib/TableLib.java Wed Feb 27 08:03:51 2013 +0000 @@ -7,6 +7,7 @@ import luan.LuanState; import luan.LuanTable; import luan.LuanFunction; +import luan.LuanLoader; import luan.LuanJavaFunction; import luan.LuanElement; import luan.LuanException; @@ -17,10 +18,9 @@ public static final String NAME = "table"; - public static final LuanFunction LOADER = new LuanFunction() { - public Object[] call(LuanState luan,Object[] args) throws LuanException { + public static final LuanLoader LOADER = new LuanLoader() { + @Override protected void load(LuanState luan) { LuanTable module = new LuanTable(); - LuanTable global = luan.global(); 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 ); @@ -32,7 +32,7 @@ } catch(NoSuchMethodException e) { throw new RuntimeException(e); } - return new Object[]{module}; + luan.loaded().put(NAME,module); } };
--- a/src/luan/lib/Utils.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/lib/Utils.java Wed Feb 27 08:03:51 2013 +0000 @@ -6,11 +6,19 @@ import java.io.Reader; import java.io.IOException; import java.net.URL; +import luan.LuanState; +import luan.LuanException; +import luan.LuanElement; public final class Utils { private Utils() {} // never + public static void checkNotNull(LuanState luan,Object v,String expected) throws LuanException { + if( v == null ) + throw new LuanException(luan,LuanElement.JAVA,"bad argument #1 ("+expected+" expected, got nil)"); + } + public static String readAll(Reader in) throws IOException {
--- a/src/luan/tools/CmdLine.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/tools/CmdLine.java Wed Feb 27 08:03:51 2013 +0000 @@ -14,7 +14,14 @@ public static void main(String[] args) { LuanState luan = LuanState.newStandard(); - BasicLib.make_standard(luan); + LuanTable env; + try { + env = luan.newEnvironment(); + } catch(LuanException e) { + System.err.println("command line error: "+e.getMessage()); + System.exit(-1); + throw new RuntimeException(); // never + } boolean interactive = false; boolean showVersion = false; int i = 0; @@ -35,7 +42,7 @@ error("'-e' needs argument"); String cmd = args[i]; try { - LuanFunction fn = BasicLib.load(luan,cmd,"(command line)"); + LuanFunction fn = BasicLib.load(luan,cmd,"(command line)",env); luan.call(fn,null,null); } catch(LuanException e) { System.err.println("command line error: "+e.getMessage()); @@ -43,7 +50,7 @@ } } else if( arg.equals("-") ) { try { - BasicLib.do_file(luan,"stdin"); + BasicLib.do_file(luan,"stdin",env); } catch(LuanException e) { System.err.println(e.getMessage()); System.exit(-1); @@ -65,9 +72,9 @@ for( int j=0; j<args.length; j++ ) { argsTable.put( j, args[j] ); } - luan.global().put("arg",argsTable); + env.put("arg",argsTable); try { - LuanFunction fn = BasicLib.load_file(luan,file); + LuanFunction fn = BasicLib.load_file(luan,file,env); luan.call(fn,null,null,varArgs); } catch(LuanException e) { // System.err.println("error: "+e.getMessage()); @@ -76,7 +83,7 @@ } } if( interactive ) - interactive(luan); + interactive(luan,env); } private static void error(String msg) { @@ -93,12 +100,12 @@ System.exit(-1); } - static void interactive(LuanState luan) { + static void interactive(LuanState luan,LuanTable env) { while( true ) { System.out.print("> "); String input = new Scanner(System.in).nextLine(); try { - Object[] rtn = luan.eval(input,"stdin"); + Object[] rtn = luan.eval(input,"stdin",env); if( rtn.length > 0 ) BasicLib.print(luan,rtn); } catch(LuanException e) {
--- a/src/luan/tools/WebRun.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/tools/WebRun.java Wed Feb 27 08:03:51 2013 +0000 @@ -10,6 +10,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import luan.LuanState; +import luan.LuanTable; import luan.LuanException; import luan.lib.HtmlLib; @@ -33,9 +34,10 @@ try { LuanState luan = newLuanState(); luan.out = out; - luan.global().put("request",request); - luan.global().put("response",response); - luan.eval(code,"WebRun"); + LuanTable env = luan.newEnvironment(); + env.put("request",request); + env.put("response",response); + luan.eval(code,"WebRun",env); } catch(LuanException e) { logger.error(null,e); response.reset();
--- a/src/luan/tools/WebServlet.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/tools/WebServlet.java Wed Feb 27 08:03:51 2013 +0000 @@ -23,8 +23,6 @@ public class WebServlet extends HttpServlet { - public static final String HTTP_SERVER = "http_server"; - protected LuanState luanState = null; protected void loadLibs(LuanState luan) throws LuanException { @@ -39,10 +37,7 @@ protected LuanState newLuanState() throws LuanException { LuanState luan = LuanCompiler.newLuanState(); loadLibs(luan); - PackageLib.require(luan,HTTP_SERVER); - Object fn = luan.global().get(HttpLib.FN_NAME); - if( !(fn instanceof LuanFunction) ) - throw new LuanException( luan, LuanElement.JAVA, "function '"+HttpLib.FN_NAME+"' not defined" ); + HttpLib.load(luan); return luan; } @@ -54,7 +49,7 @@ return luanState.deepClone(); } - protected void service(HttpServletRequest request,HttpServletResponse response) + @Override protected void service(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { try {
--- a/src/luan/tools/WebShell.java Mon Feb 25 03:53:54 2013 +0000 +++ b/src/luan/tools/WebShell.java Wed Feb 27 08:03:51 2013 +0000 @@ -15,8 +15,8 @@ import org.slf4j.LoggerFactory; import luan.LuanFunction; import luan.LuanState; +import luan.LuanTable; import luan.LuanException; -import luan.interp.LuanCompiler; import luan.lib.BasicLib; import luan.lib.HtmlLib; @@ -28,11 +28,15 @@ return LuanState.newStandard(); } - protected Object[] eval(LuanState luan,String cmd) throws LuanException { - return luan.eval(cmd,"WebShell"); + protected LuanTable newEnvironment(LuanState luan) throws LuanException { + return luan.newEnvironment(); } - protected void service(HttpServletRequest request,HttpServletResponse response) + protected Object[] eval(LuanState luan,String cmd,LuanTable env) throws LuanException { + return luan.eval(cmd,"WebShell",env); + } + + @Override protected void service(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); @@ -58,10 +62,15 @@ luan = newLuanState(); session.putValue("luan",luan); } + LuanTable env = (LuanTable)session.getValue("env"); + if( env==null ) { + env = newEnvironment(luan); + session.putValue("env",env); + } luan.out = new PrintStream(history); - luan.global().put("request",request); - luan.global().put("response",response); - Object[] result = eval(luan,cmd); + env.put("request",request); + env.put("response",response); + Object[] result = eval(luan,cmd,env); if( result.length > 0 ) { for( int i=0; i<result.length; i++ ) { if( i > 0 )