changeset 108:3c404a296995

make Package module more standard; return _ENV by default; add "import" statement; git-svn-id: https://luan-java.googlecode.com/svn/trunk@109 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Fri, 23 May 2014 03:21:54 +0000
parents dbf459397217
children 219e05867366
files src/luan/LuanLoader.java src/luan/LuanState.java src/luan/LuanTable.java src/luan/interp/ConstExpr.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/JavaLib.java src/luan/lib/MathLib.java src/luan/lib/PackageLib.java src/luan/lib/StringLib.java src/luan/lib/TableLib.java src/luan/tools/CmdLine.java src/luan/tools/WebRun.java src/luan/tools/WebShell.java
diffstat 18 files changed, 239 insertions(+), 184 deletions(-) [+]
line wrap: on
line diff
--- a/src/luan/LuanLoader.java	Mon May 19 09:17:57 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-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 May 19 09:17:57 2014 +0000
+++ b/src/luan/LuanState.java	Fri May 23 03:21:54 2014 +0000
@@ -17,13 +17,12 @@
 
 
 public abstract class LuanState implements DeepCloneable<LuanState> {
-	public static final String _G = "_G";
-
 	public final LuanBit JAVA = bit(LuanElement.JAVA);
 
+	private LuanTable global;
 	private LuanTable loaded;
 	private LuanTable preload;
-	private final List<String> defaultMods;
+	private LuanTable searchers;
 
 	public InputStream in = System.in;
 	public PrintStream out = System.out;
@@ -33,15 +32,16 @@
 	final List<StackTraceElement> stackTrace = new ArrayList<StackTraceElement>();
 
 	protected LuanState() {
+		global = new LuanTable();
+		global.put("_G",global);
 		loaded = new LuanTable();
 		preload = new LuanTable();
-		defaultMods = new ArrayList<String>();
+		searchers = new LuanTable();
 		mtGetters = new ArrayList<MetatableGetter>();
 	}
 
 	protected LuanState(LuanState luan) {
 		mtGetters = new ArrayList<MetatableGetter>(luan.mtGetters);
-		defaultMods = new ArrayList<String>(luan.defaultMods);
 	}
 
 	public final LuanState deepClone() {
@@ -49,12 +49,18 @@
 	}
 
 	@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;
 	}
@@ -63,6 +69,10 @@
 		return preload;
 	}
 
+	public final LuanTable searchers() {
+		return searchers;
+	}
+
 	public final Object get(String name) {
 		String[] a = name.split("\\.");
 		LuanTable t = loaded;
@@ -89,23 +99,10 @@
 
 	public final void load(String modName,LuanFunction loader) throws LuanException {
 		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;
+		Object mod = PackageLib.require(this,modName);
+		if( mod==null )
+			throw new RuntimeException();
+		global.put(modName,mod);
 	}
 
 	public static LuanState newStandard() {
@@ -124,8 +121,8 @@
 		}
 	}
 
-	public final Object[] eval(String cmd,String sourceName,LuanTable env) throws LuanException {
-		LuanFunction fn = BasicLib.load(this,cmd,sourceName,env);
+	public final Object[] eval(String cmd,String sourceName,boolean interactive) throws LuanException {
+		LuanFunction fn = BasicLib.load(this,cmd,sourceName,interactive);
 		return JAVA.call(fn,null);
 	}
 
--- a/src/luan/LuanTable.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/LuanTable.java	Fri May 23 03:21:54 2014 +0000
@@ -243,7 +243,17 @@
 	}
 
 	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) {
--- a/src/luan/interp/ConstExpr.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/interp/ConstExpr.java	Fri May 23 03:21:54 2014 +0000
@@ -3,18 +3,19 @@
 import luan.LuanSource;
 
 
-final class ConstExpr implements Expr {
+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 final LuanSource.Element se() {
-		return null;
-	}
 }
--- a/src/luan/interp/LuanCompiler.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/interp/LuanCompiler.java	Fri May 23 03:21:54 2014 +0000
@@ -7,15 +7,43 @@
 import luan.LuanElement;
 import luan.LuanTable;
 import luan.parser.ParseException;
+import java.util.Map;
 
 
 public final class LuanCompiler {
 	private LuanCompiler() {}  // never
 
-	public static LuanFunction compile(LuanState luan,LuanSource src,LuanTable env) throws LuanException {
-		UpValue.Getter envGetter = env!=null ? new UpValue.ValueGetter(env) : new UpValue.EnvGetter();
+	public static LuanFunction compileModule(LuanState luan,LuanSource src) throws LuanException {
+		UpValue.Getter envGetter = 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() );
+		}
 		try {
-			FnDef fnDef = LuanParser.parse(src,envGetter);
+			FnDef fnDef = parser.RequiredModule();
+			final Closure c = new Closure((LuanStateImpl)luan,fnDef);
+			return new LuanFunction() {
+				public Object[] call(LuanState luan,Object[] args) throws LuanException {
+					Object[] rtn = c.call(luan,args);
+					return rtn.length==0 ? new Object[]{c.upValues()[0].get()} : rtn;
+				}
+			};
+		} catch(ParseException e) {
+//e.printStackTrace();
+			LuanElement le = new LuanSource.CompilerElement(src);
+			throw luan.bit(le).exception( e.getFancyMessage() );
+		}
+	}
+
+	public static LuanFunction compileInteractive(LuanState luan,LuanSource src) throws LuanException {
+		UpValue.Getter envGetter = UpValue.globalGetter;
+		LuanParser parser = new LuanParser(src,envGetter);
+		try {
+			FnDef fnDef = parser.Expressions();
+			if( fnDef == null )
+				fnDef = parser.RequiredModule();
 			return new Closure((LuanStateImpl)luan,fnDef);
 		} catch(ParseException e) {
 //e.printStackTrace();
--- a/src/luan/interp/LuanParser.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/interp/LuanParser.java	Fri May 23 03:21:54 2014 +0000
@@ -11,14 +11,11 @@
 import luan.LuanSource;
 import luan.parser.Parser;
 import luan.parser.ParseException;
+import luan.lib.PackageLib;
 
 
 final class LuanParser {
 
-	static FnDef parse(LuanSource source,UpValue.Getter envGetter) throws ParseException {
-		return new LuanParser(source,envGetter).RequiredTarget();
-	}
-
 	private static final class Frame {
 		final Frame parent;
 		final List<String> symbols = new ArrayList<String>();
@@ -69,6 +66,11 @@
 			upValueSymbols.add(name);
 			return upValueSymbols.size() - 1;
 		}
+
+		void addUpValueGetter(String name,UpValue.Getter upValueGetter) {
+			upValueSymbols.add(name);
+			upValueGetters.add(upValueGetter);
+		}
 	}
 
 	private static final String _ENV = "_ENV";
@@ -77,11 +79,17 @@
 	private final LuanSource source;
 	private Frame frame;
 	private final Parser parser;
+	private final boolean interactive;
 
-	private LuanParser(LuanSource source,UpValue.Getter envGetter) {
+	LuanParser(LuanSource source,UpValue.Getter envGetter) {
 		this.source = source;
 		this.frame = new Frame(envGetter);
 		this.parser = new Parser(source.text);
+		this.interactive = envGetter==UpValue.globalGetter;
+	}
+
+	void addVar(String name,Object value) {
+		frame.addUpValueGetter(name,new UpValue.ValueGetter(value));
 	}
 
 	private LuanSource.Element se(int start) {
@@ -153,7 +161,7 @@
 		return new FnDef( se(start), stmt, frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) );
 	}
 
-	private FnDef RequiredTarget() throws ParseException {
+	FnDef Expressions() throws ParseException {
 		Spaces();
 		int start = parser.begin();
 		Expressions exprs = ExpList();
@@ -161,7 +169,12 @@
 			Stmt stmt = new ReturnStmt( se(start), exprs );
 			return parser.success(newFnDef(start,stmt));
 		}
-		parser.rollback();
+		return parser.failure(null);
+	}
+
+	FnDef RequiredModule() throws ParseException {
+		Spaces();
+		int start = parser.begin();
 		frame.isVarArg = true;
 		Stmt stmt = RequiredBlock();
 		if( parser.endOfInput() )
@@ -207,6 +220,7 @@
 		if( (stmt=ReturnStmt()) != null
 			|| (stmt=FunctionStmt()) != null
 			|| (stmt=LocalFunctionStmt()) != null
+			|| (stmt=ImportStmt()) != null
 			|| (stmt=BreakStmt()) != null
 			|| (stmt=GenericForStmt()) != null
 			|| (stmt=NumericForStmt()) != null
@@ -288,6 +302,27 @@
 		return parser.success( new SetStmt( new SetLocalVar(symbolsSize()-1), fnDef ) );
 	}
 
+	private Stmt ImportStmt() throws ParseException {
+		int start = parser.begin();
+		if( !Keyword("import") )
+			return parser.failure(null);
+		Expr importExpr = new ConstExpr(se(start),PackageLib.require);
+		String modName = StringLiteral(false);
+		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 ExpList.SingleExpList(new ConstExpr(modName)) );
+		Settable settable;
+		if( interactive ) {
+			settable = new SetTableEntry( se(start), env(), new ConstExpr(varName) );
+		} 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") )
@@ -1060,6 +1095,7 @@
 		"function",
 		"goto",
 		"if",
+		"import",
 		"in",
 		"local",
 		"nil",
--- a/src/luan/interp/LuanStateImpl.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/interp/LuanStateImpl.java	Fri May 23 03:21:54 2014 +0000
@@ -119,7 +119,7 @@
 	UpValue getUpValue(UpValue.EnvGetter getter) throws LuanException {
 		UpValue uv = envs.get(getter);
 		if( uv == null ) {
-			LuanTable env = newEnvironment();
+			LuanTable env = new LuanTable();
 			uv = new UpValue(env);
 			envs.put(getter,uv);
 		}
--- a/src/luan/interp/UpValue.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/interp/UpValue.java	Fri May 23 03:21:54 2014 +0000
@@ -102,4 +102,10 @@
 		}
 	}
 
+	static final Getter globalGetter = new Getter() {
+		public UpValue get(LuanStateImpl luan) {
+			return new UpValue(luan.global());
+		}
+	};
+
 }
--- a/src/luan/lib/BasicLib.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/lib/BasicLib.java	Fri May 23 03:21:54 2014 +0000
@@ -10,7 +10,6 @@
 import luan.LuanState;
 import luan.LuanTable;
 import luan.LuanFunction;
-import luan.LuanLoader;
 import luan.LuanJavaFunction;
 import luan.LuanException;
 import luan.LuanSource;
@@ -22,11 +21,10 @@
 
 	public static final String NAME = "Basic";
 
-	public static final LuanLoader LOADER = new LuanLoader() {
-		@Override protected void load(LuanState luan) {
+	public static final LuanFunction LOADER = new LuanFunction() {
+		@Override public Object[] call(LuanState luan,Object[] args) {
 			LuanTable module = new LuanTable();
-			LuanTable global = new LuanTable();
-			module.put( LuanState._G, global );
+			LuanTable global = luan.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 );
@@ -34,12 +32,12 @@
 				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, LuanTable.class );
+				add( global, "do_file", LuanState.class, String.class );
 				add( global, "error", LuanState.class, Object.class );
 				add( global, "get_metatable", LuanState.class, Object.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, "load", LuanState.class, String.class, String.class, Boolean.class );
+				add( global, "load_file", LuanState.class, String.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 );
@@ -55,7 +53,7 @@
 			} catch(NoSuchMethodException e) {
 				throw new RuntimeException(e);
 			}
-			luan.loaded().put(NAME,module);
+			return new Object[]{module};
 		}
 	};
 
@@ -76,22 +74,25 @@
 		return Luan.type(obj);
 	}
 
-	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(LuanState luan,String text,String sourceName,Boolean interactive) throws LuanException {
+		if( interactive!=null && interactive )
+			return LuanCompiler.compileInteractive(luan,new LuanSource(sourceName,text));
+		else
+			return LuanCompiler.compileModule(luan,new LuanSource(sourceName,text));
 	}
 
 
-	public static LuanFunction load_file(LuanState luan,String fileName,LuanTable env) throws LuanException {
+	public static LuanFunction load_file(LuanState luan,String fileName) throws LuanException {
 		try {
 			String src = fileName==null ? Utils.readAll(new InputStreamReader(System.in)) : Utils.read(new File(fileName));
-			return load(luan,src,fileName,env);
+			return load(luan,src,fileName,false);
 		} catch(IOException e) {
 			throw luan.JAVA.exception(e);
 		}
 	}
 
-	public static Object[] do_file(LuanState luan,String fileName,LuanTable env) throws LuanException {
-		LuanFunction fn = load_file(luan,fileName,env);
+	public static Object[] do_file(LuanState luan,String fileName) throws LuanException {
+		LuanFunction fn = load_file(luan,fileName);
 		return luan.JAVA.call(fn,null);
 	}
 
--- a/src/luan/lib/HtmlLib.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/lib/HtmlLib.java	Fri May 23 03:21:54 2014 +0000
@@ -3,7 +3,6 @@
 import luan.LuanState;
 import luan.LuanTable;
 import luan.LuanFunction;
-import luan.LuanLoader;
 import luan.LuanJavaFunction;
 
 
@@ -11,15 +10,15 @@
 
 	public static final String NAME = "Html";
 
-	public static final LuanLoader LOADER = new LuanLoader() {
-		@Override protected void load(LuanState luan) {
+	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);
 			}
-			luan.loaded().put(NAME,module);
+			return new Object[]{module};
 		}
 	};
 
--- a/src/luan/lib/JavaLib.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/lib/JavaLib.java	Fri May 23 03:21:54 2014 +0000
@@ -21,7 +21,6 @@
 import luan.MetatableGetter;
 import luan.LuanException;
 import luan.LuanFunction;
-import luan.LuanLoader;
 import luan.LuanJavaFunction;
 import luan.LuanElement;
 
@@ -30,28 +29,36 @@
 
 	public static final String NAME = "Java";
 
-	public static final LuanLoader LOADER = new LuanLoader() {
-		@Override protected void load(LuanState luan) {
+	public static final LuanFunction LOADER = new LuanFunction() {
+		@Override public Object[] call(LuanState luan,Object[] args) {
 			luan.addMetatableGetter(mg);
 			LuanTable module = new LuanTable();
-			LuanTable global = new LuanTable();
-			module.put( LuanState._G, global );
+			LuanTable global = luan.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) );
 				add( module, "proxy", LuanState.class, Static.class, LuanTable.class, Object.class );
 			} catch(NoSuchMethodException e) {
 				throw new RuntimeException(e);
 			}
-			luan.loaded().put(NAME,module);
+			luan.searchers().add(javaSearcher);
+			return new Object[]{module};
 		}
 	};
 
-	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 );
-	}
+	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 = JavaLib.getClass(luan,modName);
+			if( s==null )
+				return LuanFunction.EMPTY;
+			LuanFunction loader = new LuanFunction() {
+				@Override public Object[] call(LuanState luan,Object[] args) {
+					return new Object[]{s};
+				}
+			};
+			return new Object[]{loader};
+		}
+	};
 
 	private static void add(LuanTable t,String method,Class<?>... parameterTypes) {
 		try {
@@ -61,6 +68,12 @@
 		}
 	}
 
+	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 )
@@ -330,16 +343,16 @@
 			try {
 				cls = Thread.currentThread().getContextClassLoader().loadClass(name);
 			} catch(ClassNotFoundException e2) {
-				throw luan.JAVA.exception(e);
+				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>>();
 
--- a/src/luan/lib/MathLib.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/lib/MathLib.java	Fri May 23 03:21:54 2014 +0000
@@ -3,7 +3,6 @@
 import luan.LuanState;
 import luan.LuanTable;
 import luan.LuanFunction;
-import luan.LuanLoader;
 import luan.LuanJavaFunction;
 
 
@@ -11,8 +10,8 @@
 
 	public static final String NAME = "Math";
 
-	public static final LuanLoader LOADER = new LuanLoader() {
-		@Override protected void load(LuanState luan) {
+	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 );
@@ -42,7 +41,7 @@
 			} catch(NoSuchMethodException e) {
 				throw new RuntimeException(e);
 			}
-			luan.loaded().put(NAME,module);
+			return new Object[]{module};
 		}
 	};
 
--- a/src/luan/lib/PackageLib.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/lib/PackageLib.java	Fri May 23 03:21:54 2014 +0000
@@ -9,7 +9,6 @@
 import luan.LuanState;
 import luan.LuanTable;
 import luan.LuanFunction;
-import luan.LuanLoader;
 import luan.LuanJavaFunction;
 import luan.LuanElement;
 import luan.LuanException;
@@ -19,48 +18,44 @@
 
 	public static final String NAME = "Package";
 
-	public static final LuanLoader LOADER = new LuanLoader() {
-		@Override protected void load(LuanState luan) {
+	public static final LuanFunction LOADER = new LuanFunction() {
+		@Override public Object[] call(LuanState luan,Object[] args) {
 			LuanTable module = new LuanTable();
-			LuanTable global = new LuanTable();
-			module.put( LuanState._G, global );
+			LuanTable global = luan.global();
 			module.put("loaded",luan.loaded());
 			module.put("preload",luan.preload());
-			module.put("path","?.lua");
+			module.put("path","?.luan");
 			try {
-				add( global, "require", LuanState.class, String.class );
-				add( global, "module", LuanState.class, String.class, String.class );
+				global.put("require",require);
 				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)));
-			luan.loaded().put(NAME,module);
+			LuanTable searchers = luan.searchers();
+			searchers.add(preloadSearcher);
+			searchers.add(fileSearcher);
+			searchers.add(javaFileSearcher);
+			module.put("searchers",searchers);
+			return new Object[]{module};
 		}
 	};
 
+	public static final LuanFunction require;
+	static {
+		try {
+			require = new LuanJavaFunction(PackageLib.class.getMethod("require", LuanState.class, String.class),null);
+		} catch(NoSuchMethodException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
 	private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException {
 		t.put( method, new LuanJavaFunction(PackageLib.class.getMethod(method,parameterTypes),null) );
 	}
 
-	public static void module(LuanState luan,String modName,String superMod) throws LuanException {
-		LuanTable module;
-		if( superMod==null ) {
-			module = new LuanTable();
-		} else {
-			require(luan,superMod);
-			module = (LuanTable)luan.loaded().get(superMod);
-		}
-		luan.currentEnvironment().put(modName,module);
-		luan.loaded().put(modName,module);
-	}
-
-	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);
+	public static Object require(LuanState luan,String modName) throws LuanException {
+		LuanTable loaded = luan.loaded();
+		Object mod = loaded.get(modName);
 		if( mod == null ) {
 			LuanTable searchers = (LuanTable)luan.get("Package.searchers");
 			if( searchers == null )
@@ -70,18 +65,22 @@
 				Object[] a = luan.JAVA.call(searcher,"<searcher>",modName);
 				if( a.length >= 1 && a[0] instanceof LuanFunction ) {
 					LuanFunction loader = (LuanFunction)a[0];
-					luan.JAVA.call(loader,"<require \""+modName+"\">");
-					mod = (LuanTable)luan.loaded().get(modName);
-					if( mod==null )
-						throw luan.JAVA.exception( "module '"+modName+"' didn't define its module" );
+					a[0] = modName;
+					mod = Luan.first(luan.JAVA.call(loader,"<require \""+modName+"\">",a));
+					if( mod != null ) {
+						loaded.put(modName,mod);
+					} else {
+						mod = loaded.get(modName);
+						if( mod==null )
+							loaded.put(modName,true);
+					}
 					break;
 				}
 			}
 			if( mod == null )
 				throw luan.JAVA.exception( "module '"+modName+"' not found" );
 		}
-		if( env != null )
-			env.put(modName,mod);
+		return mod;
 	}
 
 	public static String search_path(String name,String path) {
@@ -93,32 +92,28 @@
 		return null;
 	}
 
-	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);
+	public static final LuanFunction fileLoader = new LuanFunction() {
+		@Override 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 fn.call(luan,new Object[]{args[0],fileName});
 		}
 	};
 
 	public static final LuanFunction fileSearcher = new LuanFunction() {
-		public Object[] call(LuanState luan,Object[] args) throws LuanException {
+		@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.EMPTY;
 			String file = search_path(modName,path);
-			return file==null ? LuanFunction.EMPTY : new Object[]{new FileLoader(file)};
+			return file==null ? LuanFunction.EMPTY : new Object[]{fileLoader,file};
 		}
 	};
 
 	public static final LuanFunction preloadSearcher = new LuanFunction() {
-		public Object[] call(LuanState luan,Object[] args) throws LuanException {
+		@Override public Object[] call(LuanState luan,Object[] args) {
 			String modName = (String)args[0];
 			Object mod = luan.preload().get(modName);
 			return new Object[]{mod};
@@ -128,18 +123,14 @@
 
 
 
-	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 {
+	public static final LuanFunction javaFileLoader = new LuanFunction() {
+		@Override public Object[] call(LuanState luan,Object[] args) throws LuanException {
+			String modName = (String)args[0];
+			URL url = (URL)args[0];
 			try {
 				String src = Utils.read(url);
-				LuanFunction fn = BasicLib.load(luan,src,url.toString(),null);
-				fn.call(luan,EMPTY);
+				LuanFunction fn = BasicLib.load(luan,src,url.toString(),false);
+				return fn.call(luan,new Object[]{args[0],url.toString()});
 			} catch(IOException e) {
 				throw luan.JAVA.exception(e);
 			}
@@ -147,7 +138,7 @@
 	};
 
 	public static final LuanFunction javaFileSearcher = new LuanFunction() {
-		public Object[] call(LuanState luan,Object[] args) throws LuanException {
+		@Override public Object[] call(LuanState luan,Object[] args) {
 			String modName = (String)args[0];
 			String path = (String)luan.get("Package.jpath");
 			if( path==null )
@@ -156,7 +147,7 @@
 				String file = s.replaceAll("\\?",modName);
 				URL url = ClassLoader.getSystemResource(file);
 				if( url != null ) {
-					return new Object[]{new JavaFileLoader(url)};
+					return new Object[]{javaFileLoader,url};
 				}
 			}
 			return LuanFunction.EMPTY;
--- a/src/luan/lib/StringLib.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/lib/StringLib.java	Fri May 23 03:21:54 2014 +0000
@@ -6,7 +6,6 @@
 import luan.LuanState;
 import luan.LuanTable;
 import luan.LuanFunction;
-import luan.LuanLoader;
 import luan.LuanJavaFunction;
 import luan.LuanElement;
 import luan.LuanException;
@@ -16,8 +15,8 @@
 
 	public static final String NAME = "String";
 
-	public static final LuanLoader LOADER = new LuanLoader() {
-		@Override protected void load(LuanState luan) {
+	public static final LuanFunction LOADER = new LuanFunction() {
+		@Override public Object[] call(LuanState luan,Object[] args) {
 			LuanTable module = new LuanTable();
 			try {
 				module.put( "byte", new LuanJavaFunction(StringLib.class.getMethod("byte_",String.class,Integer.class,Integer.class),null) );
@@ -36,7 +35,7 @@
 			} catch(NoSuchMethodException e) {
 				throw new RuntimeException(e);
 			}
-			luan.loaded().put(NAME,module);
+			return new Object[]{module};
 		}
 	};
 
--- a/src/luan/lib/TableLib.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/lib/TableLib.java	Fri May 23 03:21:54 2014 +0000
@@ -7,7 +7,6 @@
 import luan.LuanState;
 import luan.LuanTable;
 import luan.LuanFunction;
-import luan.LuanLoader;
 import luan.LuanJavaFunction;
 import luan.LuanElement;
 import luan.LuanException;
@@ -18,8 +17,8 @@
 
 	public static final String NAME = "Table";
 
-	public static final LuanLoader LOADER = new LuanLoader() {
-		@Override protected void load(LuanState luan) {
+	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 );
@@ -32,7 +31,7 @@
 			} catch(NoSuchMethodException e) {
 				throw new RuntimeException(e);
 			}
-			luan.loaded().put(NAME,module);
+			return new Object[]{module};
 		}
 	};
 
--- a/src/luan/tools/CmdLine.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/tools/CmdLine.java	Fri May 23 03:21:54 2014 +0000
@@ -14,14 +14,6 @@
 
 	public static void main(String[] args) {
 		LuanState luan = LuanState.newStandard();
-		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;
@@ -42,7 +34,7 @@
 						error("'-e' needs argument");
 					String cmd = args[i];
 					try {
-						LuanFunction fn = BasicLib.load(luan,cmd,"(command line)",env);
+						LuanFunction fn = BasicLib.load(luan,cmd,"(command line)",false);
 						luan.JAVA.call(fn,null);
 					} catch(LuanException e) {
 						System.err.println("command line error: "+e.getMessage());
@@ -50,7 +42,7 @@
 					}
 				} else if( arg.equals("-") ) {
 					try {
-						BasicLib.do_file(luan,"stdin",env);
+						BasicLib.do_file(luan,"stdin");
 					} catch(LuanException e) {
 						System.err.println(e.getMessage());
 						System.exit(-1);
@@ -72,9 +64,9 @@
 			for( int j=0; j<args.length; j++ ) {
 				argsTable.put( j, args[j] );
 			}
-			env.put("arg",argsTable);
+			luan.global().put("arg",argsTable);
 			try {
-				LuanFunction fn = BasicLib.load_file(luan,file,env);
+				LuanFunction fn = BasicLib.load_file(luan,file);
 				luan.JAVA.call(fn,null,varArgs);
 			} catch(LuanException e) {
 //				System.err.println("error: "+e.getMessage());
@@ -83,7 +75,7 @@
 			}
 		}
 		if( interactive )
-			interactive(luan,env);
+			interactive(luan);
 	}
 
 	private static void error(String msg) {
@@ -100,7 +92,7 @@
 		System.exit(-1);
 	}
 
-	static void interactive(LuanState luan,LuanTable env) {
+	static void interactive(LuanState luan) {
 		try {
 			ConsoleReader console = new ConsoleReader();
 			console.setDefaultPrompt("> ");
@@ -109,7 +101,7 @@
 				if( input==null )
 					break;
 				try {
-					Object[] rtn = luan.eval(input,"stdin",env);
+					Object[] rtn = luan.eval(input,"stdin",true);
 					if( rtn.length > 0 )
 						BasicLib.print(luan,rtn);
 				} catch(LuanException e) {
--- a/src/luan/tools/WebRun.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/tools/WebRun.java	Fri May 23 03:21:54 2014 +0000
@@ -34,10 +34,10 @@
 		try {
 			LuanState luan = newLuanState();
 			luan.out = out;
-			LuanTable env = luan.newEnvironment();
+			LuanTable env = luan.global();
 			env.put("request",request);
 			env.put("response",response);
-			luan.eval(code,"WebRun",env);
+			luan.eval(code,"WebRun",false);
 		} catch(LuanException e) {
 			logger.error(null,e);
 			response.reset();
--- a/src/luan/tools/WebShell.java	Mon May 19 09:17:57 2014 +0000
+++ b/src/luan/tools/WebShell.java	Fri May 23 03:21:54 2014 +0000
@@ -27,13 +27,13 @@
 	protected LuanState newLuanState() throws LuanException {
 		return LuanState.newStandard();
 	}
-
+/*
 	protected LuanTable newEnvironment(LuanState luan) throws LuanException {
 		return luan.newEnvironment();
 	}
-
-	protected Object[] eval(LuanState luan,String cmd,LuanTable env) throws LuanException {
-		return luan.eval(cmd,"WebShell",env);
+*/
+	protected Object[] eval(LuanState luan,String cmd) throws LuanException {
+		return luan.eval(cmd,"WebShell",true);
 	}
 
 	@Override protected void service(HttpServletRequest request,HttpServletResponse response)
@@ -62,15 +62,11 @@
 						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);
+					LuanTable env = luan.global();
 					env.put("request",request);
 					env.put("response",response);
-					Object[] result = eval(luan,cmd,env);
+					Object[] result = eval(luan,cmd);
 					if( result.length > 0 ) {
 						for( int i=0; i<result.length; i++ ) {
 							if( i > 0 )