changeset 1280:781ec0a92bb5

add Boot.luan
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 20 Dec 2018 13:38:16 -0700
parents 323743a7f317
children 7fc83fd2a39a
files src/luan/modules/Boot.luan src/luan/modules/Io.luan src/luan/modules/IoLuan.java src/luan/modules/Luan.luan src/luan/modules/PackageLuan.java src/luan/modules/Rpc.luan src/luan/modules/http/Http.luan src/luan/modules/url/LuanUrl.java
diffstat 8 files changed, 251 insertions(+), 431 deletions(-) [+]
line wrap: on
line diff
diff -r 323743a7f317 -r 781ec0a92bb5 src/luan/modules/Boot.luan
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/modules/Boot.luan	Thu Dec 20 13:38:16 2018 -0700
@@ -0,0 +1,188 @@
+java()
+local System = require "java:java.lang.System"
+local URL = require "java:java.net.URL"
+local BasicLuan = require "java:luan.modules.BasicLuan"
+local new_error = BasicLuan.new_error
+local ipairs = BasicLuan.ipairs
+local StringLuan = require "java:luan.modules.StringLuan"
+local match = StringLuan.match  -- String.match
+local IoLuan = require "java:luan.modules.IoLuan"
+local LuanUrl = require "java:luan.modules.url.LuanUrl"
+
+
+local Boot = {}
+
+
+local function error(message)
+	new_error(message).throw()
+end
+Boot.error = error
+
+
+local function new_LuanIn(io)
+	local this = {}
+	this.java = io
+	this.to_string = io.to_string
+	this.to_uri_string = io.to_uri_string
+	this.read_text = io.read_text
+	this.read_binary = io.read_binary
+	this.read_lines = io.read_lines
+	this.read_blocks = io.read_blocks
+	this.exists = io.exists
+	this.checksum = io.checksum
+	this.charset = io.charset
+	this.set_charset = io.set_charset
+	return this
+end
+Boot.new_LuanIn = new_LuanIn
+
+local function new_writer(writer)
+	local this = {}
+	this.java = writer
+	this.write = writer.write
+	this.close = writer.close
+	return this
+end
+
+function Boot.text_writer(out)
+	return new_writer( IoLuan.luanWriter(out) )
+end
+
+Boot.binary_writer = new_writer
+
+local function new_LuanIO(io)
+	local this = new_LuanIn(io)
+	this.write = io.write
+	this.write_text = io.write_text
+
+	function this.text_writer()
+		return new_writer( io.text_writer() )
+	end
+
+	function this.binary_writer()
+		return new_writer( io.binary_writer() )
+	end
+
+	return this
+end
+
+local schemes = {}
+
+function schemes.null(path)
+	return new_LuanIO( IoLuan.nullIO )
+end
+
+function schemes.string(path)
+	return new_LuanIO( IoLuan.LuanString.new(path) )
+end
+
+function schemes.classpath(path)
+	local cp = IoLuan.classpath(path)
+	return cp and new_LuanIn(cp)
+end
+
+function schemes.luan(path)
+	return schemes.classpath("luan/modules/"..path)
+end
+
+function schemes.stdin(path)
+	local Io = require "luan:Io.luan"
+	return Io.stdin
+end
+
+local function url(path,options)
+	return new_LuanIn( LuanUrl.new(URL.new(path),options) )
+end
+
+function schemes.http(path,options)
+	return url( "http:"..path, options )
+end
+
+function schemes.https(path,options)
+	return url( "https:"..path, options )
+end
+
+local function new_BaseOs(io)
+	local this = new_LuanIO(io)
+	this.wait_for = io.wait_for
+	return this
+end
+
+function schemes.os(path,options)
+	return new_BaseOs( IoLuan.LuanOs.new(path,options) )
+end
+
+function schemes.bash(path,options)
+	return new_BaseOs( IoLuan.LuanBash.new(path,options) )
+end
+
+local function new_LuanFile(io)
+	local this = new_LuanIO(io)
+	this.name = io.file.getName
+	this.is_directory = io.file.isDirectory
+	this.is_file = io.file.isFile
+	this.delete = io.delete
+	this.delete_on_exit = io.file.deleteOnExit
+	this.mkdir = io.mkdir
+	this.last_modified = io.file.lastModified
+	this.set_last_modified = io.set_last_modified
+	this.length = io.file.length
+	this.rename_to = io.rename_to
+
+	function this.child(name)
+		return new_LuanFile( io.child(name) )
+	end
+
+	function this.children()
+		local raw = io.children()
+		if raw == nil then
+			return nil
+		end
+		local rtn = {}
+		for _, child in ipairs(raw) do
+			rtn[#rtn+1] = new_LuanFile(child)
+		end
+		return rtn
+	end
+
+	function this.parent()
+		return new_LuanFile( io.parent() )
+	end
+
+	function this.canonical()
+		return new_LuanFile( io.canonical() )
+	end
+
+	function this.create_temp_file(prefix,suffix)
+		return new_LuanFile( io.create_temp_file(prefix,suffix) )
+	end
+
+	return this
+end
+
+function schemes.file(path)
+	return new_LuanFile( IoLuan.LuanFile.new(path) )
+end
+
+Boot.schemes = schemes
+
+
+local function uri(name,options)
+	local scheme, location = match( name, "^([^:]+):(.*)$" )
+	scheme or error( "invalid Io.uri name '"..name.."', missing scheme" )
+	local opener = schemes[scheme] or error( "invalid scheme '"..scheme.."' in '"+name+"'" )
+	return opener(location,options)
+end
+Boot.uri = uri
+
+
+function Boot.read(uri_str)  -- for PackageLuan.java
+	local u = uri(uri_str)
+	if u==nil or not u.exists() then
+		return nil
+	end
+	return u.read_text()
+end
+
+
+return Boot
diff -r 323743a7f317 -r 781ec0a92bb5 src/luan/modules/Io.luan
--- a/src/luan/modules/Io.luan	Tue Dec 18 12:54:55 2018 -0700
+++ b/src/luan/modules/Io.luan	Thu Dec 20 13:38:16 2018 -0700
@@ -1,18 +1,19 @@
 java()
 local IoLuan = require "java:luan.modules.IoLuan"
 local System = require "java:java.lang.System"
+local Boot = require "luan:Boot.luan"
+
 
 local Io = {}
 
 Io.ip = IoLuan.ip
 Io.my_ips = IoLuan.my_ips
 Io.read_console_line = IoLuan.read_console_line
-Io.schemes = IoLuan.newSchemes()
-Io.uri = IoLuan.uri
-Io.stdin = IoLuan.defaultStdin.table()
---Io.socket_server = IoLuan.socket_server
-Io.stdout = IoLuan.textWriter(System.out)
-Io.stderr = IoLuan.textWriter(System.err)
+Io.schemes = Boot.schemes
+Io.uri = Boot.uri
+Io.stdin = Boot.new_LuanIn( IoLuan.defaultStdin )
+Io.stdout = Boot.text_writer(System.out)
+Io.stderr = Boot.text_writer(System.err)
 Io.unrestricted = IoLuan.unrestricted
 
 -- used by http and rpc
diff -r 323743a7f317 -r 781ec0a92bb5 src/luan/modules/IoLuan.java
--- a/src/luan/modules/IoLuan.java	Tue Dec 18 12:54:55 2018 -0700
+++ b/src/luan/modules/IoLuan.java	Thu Dec 20 13:38:16 2018 -0700
@@ -16,37 +16,26 @@
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.StringWriter;
 import java.io.IOException;
 import java.io.FileNotFoundException;
 import java.net.URL;
-import java.net.Socket;
-import java.net.ServerSocket;
 import java.net.InetAddress;
 import java.net.Inet4Address;
 import java.net.NetworkInterface;
 import java.net.MalformedURLException;
 import java.net.UnknownHostException;
 import java.util.Enumeration;
-import java.util.List;
 import java.util.Map;
-import luan.Luan;
 import luan.LuanState;
 import luan.LuanTable;
 import luan.LuanFunction;
-import luan.LuanJavaFunction;
 import luan.LuanException;
 import luan.modules.url.LuanUrl;
 
 
 public final class IoLuan {
 
-	private static void add(LuanTable t,String method,Class... parameterTypes) throws NoSuchMethodException {
-		t.rawPut( method, new LuanJavaFunction(IoLuan.class.getMethod(method,parameterTypes),null) );
-	}
-
 	public static String read_console_line(String prompt) throws IOException {
 		if( prompt==null )
 			prompt = "> ";
@@ -60,7 +49,7 @@
 		public void close() throws IOException;
 	}
 
-	private static LuanWriter luanWriter(final PrintStream out) {
+	public static LuanWriter luanWriter(final PrintStream out) {
 		return new LuanWriter() {
 
 			public Object out() {
@@ -79,11 +68,7 @@
 		};
 	}
 
-	public static LuanTable textWriter(LuanState luan,final PrintStream out) {
-		return writer(luan,luanWriter(out));
-	}
-
-	private static LuanWriter luanWriter(final Writer out) {
+	public static LuanWriter luanWriter(final Writer out) {
 		return new LuanWriter() {
 
 			public Object out() {
@@ -102,43 +87,6 @@
 		};
 	}
 
-	public static LuanTable textWriter(LuanState luan,final Writer out) {
-		return writer(luan,luanWriter(out));
-	}
-
-	private static LuanTable writer(LuanState luan,LuanWriter luanWriter) {
-		LuanTable writer = new LuanTable(luan);
-		writer.rawPut( "java", luanWriter.out() );
-		try {
-			writer.rawPut( "write", new LuanJavaFunction(
-				LuanWriter.class.getMethod( "write", LuanState.class, new Object[0].getClass() ), luanWriter
-			) );
-			writer.rawPut( "close", new LuanJavaFunction(
-				LuanWriter.class.getMethod( "close" ), luanWriter
-			) );
-		} catch(NoSuchMethodException e) {
-			throw new RuntimeException(e);
-		}
-		return writer;
-	}
-
-
-	public static LuanTable binaryWriter(LuanState luan,final OutputStream out) {
-		LuanTable writer = new LuanTable(luan);
-		writer.rawPut( "java", out );
-		try {
-			writer.rawPut( "write", new LuanJavaFunction(
-				OutputStream.class.getMethod( "write", new byte[0].getClass() ), out
-			) );
-			writer.rawPut( "close", new LuanJavaFunction(
-				OutputStream.class.getMethod( "close" ), out
-			) );
-		} catch(NoSuchMethodException e) {
-			throw new RuntimeException(e);
-		}
-		return writer;
-	}
-
 	static LuanFunction lines(final BufferedReader in) {
 		return new LuanFunction() {
 			@Override public Object call(LuanState luan,Object[] args) throws LuanException {
@@ -265,46 +213,6 @@
 		public void set_charset(String charset) {
 			this.charset = charset;
 		}
-
-		public LuanTable table(LuanState luan) {
-			LuanTable tbl = new LuanTable(luan);
-			try {
-				tbl.rawPut( "java", this );
-				tbl.rawPut( "to_string", new LuanJavaFunction(
-					LuanIn.class.getMethod( "to_string" ), this
-				) );
-				tbl.rawPut( "to_uri_string", new LuanJavaFunction(
-					LuanIn.class.getMethod( "to_uri_string" ), this
-				) );
-				tbl.rawPut( "read_text", new LuanJavaFunction(
-					LuanIn.class.getMethod( "read_text", LuanState.class ), this
-				) );
-				tbl.rawPut( "read_binary", new LuanJavaFunction(
-					LuanIn.class.getMethod( "read_binary", LuanState.class ), this
-				) );
-				tbl.rawPut( "read_lines", new LuanJavaFunction(
-					LuanIn.class.getMethod( "read_lines", LuanState.class ), this
-				) );
-				tbl.rawPut( "read_blocks", new LuanJavaFunction(
-					LuanIn.class.getMethod( "read_blocks", LuanState.class, Integer.class ), this
-				) );
-				tbl.rawPut( "exists", new LuanJavaFunction(
-					LuanIn.class.getMethod( "exists", LuanState.class ), this
-				) );
-				tbl.rawPut( "checksum", new LuanJavaFunction(
-					LuanIn.class.getMethod( "checksum", LuanState.class ), this
-				) );
-				tbl.rawPut( "charset", new LuanJavaFunction(
-					LuanIn.class.getMethod( "charset" ), this
-				) );
-				tbl.rawPut( "set_charset", new LuanJavaFunction(
-					LuanIn.class.getMethod( "set_charset", String.class ), this
-				) );
-			} catch(NoSuchMethodException e) {
-				throw new RuntimeException(e);
-			}
-			return tbl;
-		}
 	}
 
 	public static final LuanIn defaultStdin = new LuanIn() {
@@ -373,12 +281,12 @@
 			throw new LuanException( "bad argument #1 to 'write' (string or binary or Io.uri expected)" );
 		}
 
-		public LuanTable text_writer(LuanState luan) throws IOException {
-			return textWriter(luan,new BufferedWriter(writer()));
+		public LuanWriter text_writer() throws IOException {
+			return luanWriter(new BufferedWriter(writer()));
 		}
 
-		public LuanTable binary_writer(LuanState luan) throws IOException {
-			return binaryWriter(luan,new BufferedOutputStream(outputStream()));
+		public OutputStream binary_writer() throws IOException {
+			return new BufferedOutputStream(outputStream());
 		}
 
 		public void write_text(LuanState luan,Object... args) throws LuanException, IOException {
@@ -386,30 +294,9 @@
 			luanWriter.write(luan,args);
 			luanWriter.close();
 		}
-
-		@Override public LuanTable table(LuanState luan) {
-			LuanTable tbl = super.table(luan);
-			try {
-				tbl.rawPut( "write", new LuanJavaFunction(
-					LuanIO.class.getMethod( "write", LuanState.class, Object.class ), this
-				) );
-				tbl.rawPut( "text_writer", new LuanJavaFunction(
-					LuanIO.class.getMethod( "text_writer", LuanState.class ), this
-				) );
-				tbl.rawPut( "binary_writer", new LuanJavaFunction(
-					LuanIO.class.getMethod( "binary_writer", LuanState.class ), this
-				) );
-				tbl.rawPut( "write_text", new LuanJavaFunction(
-					LuanIO.class.getMethod( "write_text", LuanState.class, new Object[0].getClass() ), this
-				) );
-			} catch(NoSuchMethodException e) {
-				throw new RuntimeException(e);
-			}
-			return tbl;
-		}
 	}
 
-	private static final LuanIO nullIO = new LuanIO() {
+	public static final LuanIO nullIO = new LuanIO() {
 		private final InputStream in = new InputStream() {
 			@Override public int read() {
 				return -1;
@@ -440,7 +327,8 @@
 	public static final class LuanString extends LuanIO {
 		private String s;
 
-		private LuanString(String s) {
+		public LuanString(String s) throws LuanException {
+			Utils.checkNotNull(s);
 			this.s = s;
 		}
 
@@ -472,8 +360,8 @@
 			return true;
 		}
 
-		@Override public LuanTable text_writer(LuanState luan) throws IOException {
-			LuanWriter luanWriter = new LuanWriter() {
+		@Override public LuanWriter text_writer() {
+			return new LuanWriter() {
 				private final Writer out = new StringWriter();
 
 				public Object out() {
@@ -490,13 +378,16 @@
 					s = out.toString();
 				}
 			};
-			return writer(luan,luanWriter);
 		}
 	}
 
 	public static final class LuanFile extends LuanIO {
 		public final File file;
 
+		public LuanFile(LuanState luan,String path) throws LuanException {
+			this(luan,new File(path));
+		}
+
 		private LuanFile(LuanState luan,File file) throws LuanException {
 			this(file);
 			check(luan,"file:"+file.toString());
@@ -522,8 +413,8 @@
 			return "file:" + file.toString();
 		}
 
-		public LuanTable child(LuanState luan,String name) throws LuanException {
-			return new LuanFile(luan,new File(file,name)).table(luan);
+		public LuanFile child(LuanState luan,String name) throws LuanException {
+			return new LuanFile(luan,new File(file,name));
 		}
 
 		public LuanTable children(LuanState luan) throws LuanException {
@@ -532,16 +423,16 @@
 				return null;
 			LuanTable list = new LuanTable(luan);
 			for( File f : files ) {
-				list.rawPut(list.rawLength()+1,new LuanFile(luan,f).table(luan));
+				list.rawPut(list.rawLength()+1,new LuanFile(luan,f));
 			}
 			return list;
 		}
 
-		public LuanTable parent(LuanState luan) throws LuanException, IOException {
+		public LuanFile parent(LuanState luan) throws LuanException, IOException {
 			File parent = file.getParentFile();
 			if( parent==null )
 				parent = file.getCanonicalFile().getParentFile();
-			return new LuanFile(luan,parent).table(luan);
+			return new LuanFile(luan,parent);
 		}
 
 		@Override public boolean exists(LuanState luan) {
@@ -556,13 +447,13 @@
 				throw new LuanException("couldn't rename file "+file+" to "+dest);
 		}
 
-		public LuanTable canonical(LuanState luan) throws LuanException, IOException {
-			return new LuanFile(luan,file.getCanonicalFile()).table(luan);
+		public LuanFile canonical(LuanState luan) throws LuanException, IOException {
+			return new LuanFile(luan,file.getCanonicalFile());
 		}
 
-		public LuanTable create_temp_file(LuanState luan,String prefix,String suffix) throws LuanException, IOException {
+		public LuanFile create_temp_file(LuanState luan,String prefix,String suffix) throws LuanException, IOException {
 			File tmp = File.createTempFile(prefix,suffix,file);
-			return new LuanFile(luan,tmp).table(luan);
+			return new LuanFile(luan,tmp);
 		}
 
 		public void delete() throws LuanException {
@@ -592,77 +483,9 @@
 			if( !file.setLastModified(time) )
 				throw new LuanException("couldn't set_last_modified on "+file);
 		}
-
-		@Override public LuanTable table(LuanState luan) {
-			LuanTable tbl = super.table(luan);
-			try {
-				tbl.rawPut( "name", new LuanJavaFunction(
-					File.class.getMethod( "getName" ), file
-				) );
-				tbl.rawPut( "is_directory", new LuanJavaFunction(
-					File.class.getMethod( "isDirectory" ), file
-				) );
-				tbl.rawPut( "is_file", new LuanJavaFunction(
-					File.class.getMethod( "isFile" ), file
-				) );
-				tbl.rawPut( "delete", new LuanJavaFunction(
-					LuanFile.class.getMethod( "delete" ), this
-				) );
-				tbl.rawPut( "delete_on_exit", new LuanJavaFunction(
-					File.class.getMethod( "deleteOnExit" ), file
-				) );
-				tbl.rawPut( "mkdir", new LuanJavaFunction(
-					LuanFile.class.getMethod( "mkdir" ), this
-				) );
-				tbl.rawPut( "last_modified", new LuanJavaFunction(
-					File.class.getMethod( "lastModified" ), file
-				) );
-				tbl.rawPut( "set_last_modified", new LuanJavaFunction(
-					LuanFile.class.getMethod( "set_last_modified", Long.TYPE ), this
-				) );
-				tbl.rawPut( "length", new LuanJavaFunction(
-					File.class.getMethod( "length" ), file
-				) );
-				tbl.rawPut( "child", new LuanJavaFunction(
-					LuanFile.class.getMethod( "child", LuanState.class, String.class ), this
-				) );
-				tbl.rawPut( "children", new LuanJavaFunction(
-					LuanFile.class.getMethod( "children", LuanState.class ), this
-				) );
-				tbl.rawPut( "parent", new LuanJavaFunction(
-					LuanFile.class.getMethod( "parent", LuanState.class ), this
-				) );
-				tbl.rawPut( "rename_to", new LuanJavaFunction(
-					LuanFile.class.getMethod( "rename_to", Object.class ), this
-				) );
-				tbl.rawPut( "canonical", new LuanJavaFunction(
-					LuanFile.class.getMethod( "canonical", LuanState.class ), this
-				) );
-				tbl.rawPut( "create_temp_file", new LuanJavaFunction(
-					LuanFile.class.getMethod( "create_temp_file", LuanState.class, String.class, String.class ), this
-				) );
-			} catch(NoSuchMethodException e) {
-				throw new RuntimeException(e);
-			}
-			return tbl;
-		}
 	}
 
-	public static LuanTable null_(LuanState luan,String ignore) {
-		return nullIO.table(luan);
-	}
-
-	public static LuanTable string(LuanState luan,String s) throws LuanException {
-		Utils.checkNotNull(s);
-		return new LuanString(s).table(luan);
-	}
-
-	public static LuanTable file(LuanState luan,String name) throws LuanException {
-		File file = new File(name);
-		return new LuanFile(luan,file).table(luan);
-	}
-
-	public static LuanTable classpath(LuanState luan,String name) throws LuanException {
+	public static LuanUrl classpath(LuanState luan,String name) throws LuanException {
 		if( name.contains("//") )
 			return null;
 		String path = name;
@@ -688,136 +511,11 @@
 			}
 		}
 		if( url != null )
-			return new LuanUrl(url,null).table(luan);
+			return new LuanUrl(url,null);
 
 		return null;
 	}
 
-	private static LuanTable url(LuanState luan,String url,LuanTable options) throws IOException, LuanException {
-		return new LuanUrl(new URL(url),options).table(luan);
-	}
-
-	public static LuanTable http(LuanState luan,String path,LuanTable options) throws IOException, LuanException {
-		return url(luan,"http:"+path,options);
-	}
-
-	public static LuanTable https(LuanState luan,String path,LuanTable options) throws IOException, LuanException {
-		return url(luan,"https:"+path,options);
-	}
-
-	public static LuanTable luan(LuanState luan,String path) throws LuanException {
-		return classpath( luan, "luan/modules/" + path );
-	}
-
-	public static LuanTable stdin(LuanState luan) throws LuanException {
-		LuanTable io = (LuanTable)PackageLuan.require(luan,"luan:Io.luan");
-		return (LuanTable)io.get("stdin");
-	}
-
-	public static LuanTable newSchemes(LuanState luan) {
-		LuanTable schemes = new LuanTable(luan);
-		try {
-			schemes.rawPut( "null", new LuanJavaFunction(IoLuan.class.getMethod("null_",LuanState.class,String.class),null) );
-			add( schemes, "string", LuanState.class, String.class );
-			add( schemes, "file", LuanState.class, String.class );
-			add( schemes, "classpath", LuanState.class, String.class );
-//			add( schemes, "socket", String.class );
-			add( schemes, "http", LuanState.class, String.class, LuanTable.class );
-			add( schemes, "https", LuanState.class, String.class, LuanTable.class );
-			add( schemes, "luan", LuanState.class, String.class );
-			add( schemes, "stdin", LuanState.class );
-			add( schemes, "os", LuanState.class, String.class, LuanTable.class );
-			add( schemes, "bash", LuanState.class, String.class, LuanTable.class );
-		} catch(NoSuchMethodException e) {
-			throw new RuntimeException(e);
-		}
-		return schemes;
-	}
-
-	private static LuanTable schemes(LuanState luan) throws LuanException {
-		LuanTable t = (LuanTable)PackageLuan.loaded(luan).rawGet("luan:Io.luan");
-		if( t == null )
-			return newSchemes(luan);
-		t = (LuanTable)t.get("schemes");
-		if( t == null )
-			return newSchemes(luan);
-		return t;
-	}
-
-	public static LuanTable uri(LuanState luan,String name,LuanTable options) throws LuanException {
-		int i = name.indexOf(':');
-		if( i == -1 )
-			throw new LuanException( "invalid Io.uri name '"+name+"', missing scheme" );
-		String scheme = name.substring(0,i);
-		String location = name.substring(i+1);
-		LuanTable schemes = schemes(luan);
-		LuanFunction opener = (LuanFunction)schemes.get(scheme);
-		if( opener == null )
-			throw new LuanException( "invalid scheme '"+scheme+"' in '"+name+"'" );
-		return (LuanTable)Luan.first(opener.call(luan,new Object[]{location,options}));
-	}
-/*
-	public static final class LuanSocket extends LuanIO {
-		public final Socket socket;
-
-		private LuanSocket(String host,int port) throws LuanException {
-			try {
-				this.socket = new Socket(host,port);
-			} catch(IOException e) {
-				throw new LuanException(e.toString());
-			}
-		}
-
-		private LuanSocket(Socket socket) {
-			this.socket = socket;
-		}
-
-		@Override public InputStream inputStream() throws IOException {
-			return socket.getInputStream();
-		}
-
-		@Override OutputStream outputStream() throws IOException {
-			return socket.getOutputStream();
-		}
-
-		@Override public String to_string() {
-			return socket.toString();
-		}
-
-		@Override public String to_uri_string() {
-			throw new UnsupportedOperationException();
-		}
-	}
-
-	public static LuanTable socket(String name) throws LuanException, IOException {
-		int i = name.indexOf(':');
-		if( i == -1 )
-			throw new LuanException( "invalid socket '"+name+"', format is: <host>:<port>" );
-		String host = name.substring(0,i);
-		String portStr = name.substring(i+1);
-		int port = Integer.parseInt(portStr);
-		return new LuanSocket(host,port).table();
-	}
-
-	public static LuanFunction socket_server(int port) throws IOException {
-		final ServerSocket ss = new ServerSocket(port);
-		return new LuanFunction() {
-			@Override public Object call(LuanState luan,Object[] args) throws LuanException {
-				try {
-					if( args.length > 0 ) {
-						if( args.length > 1 || !"close".equals(args[0]) )
-							throw new LuanException( "the only argument allowed is 'close'" );
-						ss.close();
-						return null;
-					}
-					return new LuanSocket(ss.accept()).table();
-				} catch(IOException e) {
-					throw new LuanException(e);
-				}
-			}
-		};
-	}
-*/
 
 	public static class BaseOs extends LuanIO {
 		private final String cmd;
@@ -881,45 +579,24 @@
 			wait_for();
 			return s;
 		}
-
-		@Override public LuanTable table(LuanState luan) {
-			LuanTable tbl = super.table(luan);
-			try {
-				tbl.rawPut( "wait_for", new LuanJavaFunction(
-					BaseOs.class.getMethod( "wait_for" ), this
-				) );
-			} catch(NoSuchMethodException e) {
-				throw new RuntimeException(e);
-			}
-			return tbl;
-		}
 	}
 
 	public static final class LuanOs extends BaseOs {
-		private LuanOs(LuanState luan,String cmd,LuanTable options) throws IOException, LuanException {
+		public LuanOs(LuanState luan,String cmd,LuanTable options) throws IOException, LuanException {
 			super(cmd,options);
 			check(luan,"os:"+cmd);
 			this.proc = Runtime.getRuntime().exec(cmd,null,dir);
 		}
 	}
 
-	public static LuanTable os(LuanState luan,String cmd,LuanTable options) throws IOException, LuanException {
-		return new LuanOs(luan,cmd,options).table(luan);
-	}
-
 	public static final class LuanBash extends BaseOs {
-		private LuanBash(LuanState luan,String cmd,LuanTable options) throws IOException, LuanException {
+		public LuanBash(LuanState luan,String cmd,LuanTable options) throws IOException, LuanException {
 			super(cmd,options);
 			check(luan,"bash:"+cmd);
 			this.proc = Runtime.getRuntime().exec(new String[]{"bash","-c",cmd},null,dir);
 		}
 	}
 
-	public static LuanTable bash(LuanState luan,String cmd,LuanTable options) throws IOException, LuanException {
-		return new LuanBash(luan,cmd,options).table(luan);
-	}
-
-
 
 	public static class LuanInput extends LuanIn {
 		private final InputStream in;
@@ -967,36 +644,6 @@
 		return tbl;
 	}
 
-/*
-	// files maps zip name to uri
-	public static void zip(LuanState luan,String zipUri,LuanTable files) throws LuanException, IOException {
-		Object obj = uri(luan,zipUri,null).rawGet("java");
-		if( !(obj instanceof LuanIO) )
-			throw new LuanException("invalid uri for zip");
-		LuanIO zipIo = (LuanIO)obj;
-		ZipOutputStream out = new ZipOutputStream(zipIo.outputStream());
-		for( Map.Entry<Object,Object> entry : files.iterable(luan) ) {
-			obj = entry.getKey();
-			if( !(obj instanceof String) )
-				throw new LuanException("zip file table keys must be strings");
-			String fileName = (String)obj;
-			obj = entry.getValue();
-			if( !(obj instanceof String) )
-				throw new LuanException("zip file table values must be strings");
-			String uriStr = (String)obj;
-			out.putNextEntry(new ZipEntry(fileName));
-			obj = uri(luan,uriStr,null).rawGet("java");
-			if( !(obj instanceof LuanIn) )
-				throw new LuanException("invalid uri for zip");
-			LuanIn zipIn = (LuanIn)obj;
-			InputStream in = zipIn.inputStream();
-			Utils.copyAll(in,out);
-			in.close();
-			out.closeEntry();
-		}
-		out.close();
-	}
-*/
 
 	// security
 
diff -r 323743a7f317 -r 781ec0a92bb5 src/luan/modules/Luan.luan
--- a/src/luan/modules/Luan.luan	Tue Dec 18 12:54:55 2018 -0700
+++ b/src/luan/modules/Luan.luan	Thu Dec 20 13:38:16 2018 -0700
@@ -1,8 +1,10 @@
 java()
 local BasicLuan = require "java:luan.modules.BasicLuan"
+local Boot = require "luan:Boot.luan"
 
 local Luan = {}
 
+Luan.error = Boot.error
 Luan.get_metatable = BasicLuan.get_metatable
 Luan.hash_code = BasicLuan.hash_code
 Luan.ipairs = BasicLuan.ipairs
@@ -29,10 +31,6 @@
 
 Luan.VERSION = Luan.do_file "classpath:luan/version.luan"
 
-function Luan.error(message)
-	Luan.new_error(message).throw()
-end
-
 function Luan.eval(s,source_name)
 	return Luan.load( "return "..s, source_name or "eval" )()
 end
diff -r 323743a7f317 -r 781ec0a92bb5 src/luan/modules/PackageLuan.java
--- a/src/luan/modules/PackageLuan.java	Tue Dec 18 12:54:55 2018 -0700
+++ b/src/luan/modules/PackageLuan.java	Thu Dec 20 13:38:16 2018 -0700
@@ -1,5 +1,7 @@
 package luan.modules;
 
+import java.io.Reader;
+import java.io.InputStreamReader;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collections;
@@ -43,7 +45,22 @@
 		LuanTable loaded = loaded(luan);
 		Object mod = loaded.rawGet(modName);
 		if( mod == null ) {
-			if( modName.startsWith("java:") ) {
+			if( modName.equals("luan:Boot.luan") ) {
+				String src;
+				try {
+					Reader in = new InputStreamReader(ClassLoader.getSystemResourceAsStream("luan/modules/Boot.luan"));
+					src = Utils.readAll(in);
+					in.close();
+				} catch(IOException e) {
+					throw new RuntimeException(e);
+				}
+				LuanFunction loader = Luan.load(src,modName);
+				mod = Luan.first(
+					loader.call(luan,new Object[]{modName})
+				);
+				if( mod == null )
+					throw new RuntimeException();
+			} else if( modName.startsWith("java:") ) {
 				mod = JavaLuan.load(luan,modName.substring(5));
 				if( mod == null )
 					mod = Boolean.FALSE;
@@ -70,25 +87,9 @@
 	}
 
 	static String read(LuanState luan,String uri) throws LuanException {
-		LuanTable t = IoLuan.uri(luan,uri,null);
-		if( t == null )
-			return null;
-/*
-		LuanFunction existsFn = (LuanFunction)t.get(luan,"exists");
-		boolean exists = (Boolean)Luan.first(existsFn.call(luan));
-		if( !exists )
-			return null;
-		LuanFunction reader = (LuanFunction)t.get(luan,"read_text");
-		return (String)Luan.first(reader.call(luan));
-*/
-		IoLuan.LuanIn in = (IoLuan.LuanIn)t.rawGet("java");
-		try {
-			if( !in.exists(luan) )
-				return null;
-			return in.read_text(luan);
-		} catch(IOException e) {
-			throw new LuanException(e);
-		}
+		LuanTable boot = (LuanTable)PackageLuan.require(luan,"luan:Boot.luan");
+		LuanFunction read = (LuanFunction)boot.get("read");
+		return (String)Luan.first(read.call(luan,new Object[]{uri}));
 	}
 
 	public static void enableLoad(LuanState luan,String... mods) throws LuanException {
diff -r 323743a7f317 -r 781ec0a92bb5 src/luan/modules/Rpc.luan
--- a/src/luan/modules/Rpc.luan	Tue Dec 18 12:54:55 2018 -0700
+++ b/src/luan/modules/Rpc.luan	Thu Dec 20 13:38:16 2018 -0700
@@ -19,6 +19,7 @@
 local try = Luan.try or error()
 local ipairs = Luan.ipairs or error()
 local type = Luan.type or error()
+local Boot = require "luan:Boot.luan"
 local Io = require "luan:Io.luan"
 local Thread = require "luan:Thread.luan"
 local Table = require "luan:Table.luan"
@@ -62,7 +63,7 @@
 		if type == "binary" then
 			list[i_in] = JavaUtils.readAll(binary_in)
 		elseif type == "input" then
-			list[i_in] = IoLuan.LuanInput.new(binary_in).table()
+			list[i_in] = Boot.new_LuanIn( IoLuan.LuanInput.new(binary_in) )
 		else
 			error(type)
 		end
diff -r 323743a7f317 -r 781ec0a92bb5 src/luan/modules/http/Http.luan
--- a/src/luan/modules/http/Http.luan	Tue Dec 18 12:54:55 2018 -0700
+++ b/src/luan/modules/http/Http.luan	Thu Dec 20 13:38:16 2018 -0700
@@ -14,7 +14,7 @@
 local lower = String.lower or error()
 local matches = String.matches or error()
 local trim = String.trim or error()
-local IoLuan = require "java:luan.modules.IoLuan"
+local Boot = require "luan:Boot.luan"
 local LuanJava = require "java:luan.Luan"
 local Request = require "java:luan.webserver.Request"
 local Response = require "java:luan.webserver.Response"
@@ -134,13 +134,13 @@
 		this.writer and "writer already set"
 		this.writer = ResponseOutputStream.new(this.java)
 		this.writer = OutputStreamWriter.new(this.writer)
-		return IoLuan.textWriter(this.writer)
+		return Boot.text_writer(this.writer)
 	end
 
 	function this.binary_writer()
 		this.writer and "writer already set"
 		this.writer = ResponseOutputStream.new(this.java)
-		return IoLuan.binaryWriter(this.writer)
+		return Boot.binary_writer(this.writer)
 	end
 
 	return this
diff -r 323743a7f317 -r 781ec0a92bb5 src/luan/modules/url/LuanUrl.java
--- a/src/luan/modules/url/LuanUrl.java	Tue Dec 18 12:54:55 2018 -0700
+++ b/src/luan/modules/url/LuanUrl.java	Thu Dec 20 13:38:16 2018 -0700
@@ -277,21 +277,5 @@
 	@Override public String to_uri_string() {
 		return url.toString();
 	}
-/*
-	public String post(String postS) throws IOException {
-		return new UrlCall(url).post(postS);
-	}
 
-	@Override public LuanTable table() {
-		LuanTable tbl = super.table();
-		try {
-			tbl.rawPut( "post", new LuanJavaFunction(
-				LuanUrl.class.getMethod( "post", String.class ), this
-			) );
-		} catch(NoSuchMethodException e) {
-			throw new RuntimeException(e);
-		}
-		return tbl;
-	}
-*/
 }