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 )