shithub: lu9

Download patch

ref: e2c68ac539177f6ff4191e6a5c30ec4c25100abe
parent: 01d4cb8f03958e86a1c01ce3b2f6fb08df9a89db
author: kvik <[email protected]>
date: Thu Apr 8 18:34:28 EDT 2021

It's lu9 now

--- /dev/null
+++ b/lu9.c
@@ -1,0 +1,227 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+extern int luaopen_p9(lua_State*);
+extern int luaopen_lpeg(lua_State*);
+
+luaL_Reg preloadlibs[] = {
+	{"p9.raw", luaopen_p9},
+	{"lpeg", luaopen_lpeg},
+	{nil, nil}
+};
+
+char flag[] = {
+	['i'] = 0, /* interactive */
+	['v'] = 0, /* print version */
+	['w'] = 0, /* enable warnings */
+};
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [-ivw] [script] [arg ...]\n", argv0);
+	exits("usage");
+}
+
+int
+iscons(int fd)
+{
+	int n, c;
+	char buf[64];
+	
+	if(fd2path(fd, buf, sizeof buf) != 0)
+		sysfatal("fd2path: %r");
+	n = strlen(buf);
+	c = strlen("/dev/cons");
+	return n >= c && strcmp(buf + n - c, "/dev/cons") == 0;
+}
+
+void
+luaerror(lua_State *L)
+{
+	fprint(2, "%s: %s\n", argv0, lua_tostring(L, -1));
+	lua_pop(L, 1);
+}
+
+int
+pcallerror(lua_State *L)
+{
+	const char *m;
+	
+	m = lua_tostring(L, 1);
+	if(m == nil){
+		if(luaL_callmeta(L, 1, "__tostring") && lua_type(L, -1) == LUA_TSTRING)
+			return 1;
+		else
+			m = lua_pushfstring(L,
+				"(error object is a %s value)", luaL_typename(L, 1));
+	}
+	luaL_traceback(L, L, m, 1);
+	return 1;
+}
+
+int
+pcall(lua_State *L, int narg, int nres)
+{
+	int r, base;
+	
+	base = lua_gettop(L) - narg;
+	lua_pushcfunction(L, pcallerror);
+	lua_insert(L, base);
+	r = lua_pcall(L, narg, nres, base);
+	lua_remove(L, base);
+	return r;
+}
+
+int
+pushargs(lua_State *L)
+{
+	int i, n;
+	
+	/* Push the 'arg' array to stack */
+	if(lua_getglobal(L, "arg") != LUA_TTABLE)
+		luaL_error(L, "'arg' is not a table");
+	n = luaL_len(L, -1);
+	luaL_checkstack(L, n + 1, "too many arguments");
+	for(i = 1; i <= n; i++)
+		lua_rawgeti(L, -i, i);
+	lua_remove(L, -i);
+	return n;
+}
+
+int
+runrepl(lua_State *L)
+{
+	int r, narg;
+	char *ln;
+	Biobuf bin;
+	
+	if(Binit(&bin, 0, OREAD) == -1)
+		sysfatal("Binit: %r");
+	r = LUA_OK;
+	while(fprint(2, "> "), (ln = Brdstr(&bin, '\n', 1)) != nil){
+		if(luaL_loadstring(L, ln) != LUA_OK){
+			luaerror(L);
+			continue;
+		}
+		narg = pushargs(L);
+		if((r = pcall(L, narg, LUA_MULTRET)) != LUA_OK)
+			luaerror(L);
+	}
+	Bterm(&bin);
+	return r;
+}
+
+int
+runfile(lua_State *L, char *file)
+{
+	int narg, r;
+	
+	if((r = luaL_loadfile(L, file)) == LUA_OK){
+		narg = pushargs(L);
+		r = pcall(L, narg, LUA_MULTRET);
+	}
+	if(r != LUA_OK)
+		luaerror(L);
+	return r;
+}
+
+int
+luamain(lua_State *L)
+{
+	int argc, i;
+	char **argv, *file;
+	
+	argc = lua_tointeger(L, 1);
+	argv = lua_touserdata(L, 2);
+	file = argv[0];
+	
+	if(flag['w'])
+		lua_warning(L, "@on", 0);
+	
+	/* GC in generational mode */
+	lua_gc(L, LUA_GCGEN, 0, 0);
+
+	/* Signal for libraries to ignore LUA_* env. vars */
+	lua_pushboolean(L, 1);
+	lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
+	
+	luaL_openlibs(L);
+	/*
+	 * Preload additional libraries.
+	 * Because dynamic loading of C libraries is not
+	 * supported these must be manually loaded by the host,
+	 * as in the case of standard libraries above.
+	 * An alternative is to register library loaders in the
+	 * package.preload table, which makes them run at the
+	 * time the program requires the library.
+	 */
+	luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
+	for(luaL_Reg *lib = preloadlibs; lib->func; lib++){
+		lua_pushcfunction(L, lib->func);
+		lua_setfield(L, -2, lib->name);
+	}
+	lua_pop(L, 1);
+	
+	/* Create global 'arg' table */
+	lua_createtable(L, argc, 0);
+	lua_pushstring(L, argv0);
+	lua_rawseti(L, -2, 0);
+	for(i = 1; i < argc; i++){
+		lua_pushstring(L, argv[i]);
+		lua_rawseti(L, -2, i);
+	}
+	lua_setglobal(L, "arg");
+	
+	if(file == nil){
+		file = "/fd/0";
+		if(flag['i'] && iscons(0))
+			file = nil;
+	}
+	if(file != nil)
+		runfile(L, file);
+	if(flag['i'])
+		runrepl(L);
+
+	lua_pushboolean(L, 1);
+	return 1;
+}
+
+void
+main(int argc, char *argv[])
+{
+	int r, v;
+	lua_State *L;
+	
+	ARGBEGIN{
+	case 'i': flag['i'] = 1; break;
+	case 'v': flag['v'] += 1; break;
+	case 'w': flag['w'] = 1; break;
+	default: usage();
+	}ARGEND;
+	if(flag['v']){
+		if(flag['v'] == 1)
+			print("%s\n", LUA_VERSION_MAJOR "." LUA_VERSION_MINOR);
+		else
+			print("%s\n", LUA_RELEASE);
+		exits(nil);
+	}
+
+	setfcr(getfcr() & ~(FPZDIV | FPOVFL | FPINVAL));
+	if((L = luaL_newstate()) == nil)
+		sysfatal("out of memory");
+	lua_pushcfunction(L, luamain);
+	lua_pushinteger(L, argc);
+	lua_pushlightuserdata(L, argv);
+	r = lua_pcall(L, 2, 1, 0);
+	if(r != LUA_OK)
+		luaerror(L);
+	v = lua_toboolean(L, -1);
+	lua_close(L);
+	exits(r == LUA_OK && v == 1 ? nil : "errors");
+}
--- /dev/null
+++ b/lu9.man
@@ -1,0 +1,132 @@
+.TH LUA9 1
+.SH NAME
+lua9 \- Lua standalone for Plan 9
+.SH SYNOPSIS
+.B lua9
+.RB [ -ivw ]
+.RI [ script ]
+.RI [ args
+.IR ... ]
+.SH DESCRIPTION
+.PP
+.I Lua9
+is an interpreter for Lua as a standalone language.
+It runs Lua scripts and provides a basic REPL for
+interactive usage.
+.PP
+In addition to standard Lua libraries it is packed
+with several others which are likely to be useful
+for writing Plan 9 programs.
+This includes the library of bindings for the
+.I Plan 9
+C library
+and the
+.IR lpeg
+text processing library.
+Others are likely to be included in the future,
+guided by user demand.
+.SH USAGE
+.B Lua9
+runs in script mode by default, loading the
+.I script
+file if given, or loading the script from standard input
+if not.
+Given the
+.B -i
+option an interactive REPL is entered after the script
+finishes, or immediately if no script is given.
+.PP
+A script (a line in interactive mode) is compiled as
+a Lua chunk and called with variable number of arguments
+.I args
+given after the
+.I script
+on the command line.
+The arguments are also loaded into the global
+.IR arg 
+table, with
+.B arg[0]
+holding the executable (not script) name, and the elements
+.B arg[1]
+to
+.B arg[N]
+holding the respective arguments.
+.PP
+The
+.B -w
+option turns on the Lua warning system.
+.PP
+The
+.B -v
+option prints Lua version and exits.
+.SS MODULES
+The default
+.B package.path
+is set to:
+.PP
+.EX
+/sys/lib/lua/5.4/?.lua
+/sys/lib/lua/5.4/?/init.lua
+\&./?.lua
+\&./?/init.lua
+.EE
+.PP
+The
+.B package.cpath
+does nothing, as dynamically loaded C modules aren't supported.
+.SH EXAMPLES
+.PP
+Run a script with three arguments:
+.PP
+.EX
+; lua9 main.lua a b c
+.EE
+.PP
+Same as above, entering REPL after the script finishes:
+.PP
+.EX
+; lua9 -i main.lua a b c
+.EE
+.PP
+Run REPL with command line arguments:
+.PP
+.EX
+; lua9 -i /dev/null a b c
+.EE
+.PP
+An executable Lua program can be created as expected:
+.PP
+.EX
+; cat /bin/prog
+#!/bin/lua9
+io.write("hello world\\n")
+; chmod +x /bin/prog
+; prog
+.EE
+.SH SEE ALSO
+.PP
+Lua Reference Manual \- https://lua.org/manual/5.4
+.SH SOURCE
+.PP
+The interpreter and libraries making up the wider "Lua9"
+project can be found at:
+.PP
+.EE
+https://sr.ht/~kvik/lua9/
+.EX
+.SH BUGS
+.PP
+The interpreter interface and runtime environment resembles
+but is incompatible with the official
+.BR lua (1)
+version -- this is largely intentional to keep the code and
+runtime behaviour simple. Compatibility features might be
+accepted if they prove necessary in practice.
+.PP
+The Plan 9 libc bindings are WIP.
+.PP
+There's no way to pre-compile Lua code, as with
+.BR luac (1) .
+Patches accepted.
+.PP
+REPL is crude.  Patches accepted.
--- a/lua9.c
+++ /dev/null
@@ -1,199 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-
-#include <lua.h>
-#include <lauxlib.h>
-#include <lualib.h>
-
-char flag[] = {
-	['i'] = 0, /* interactive */
-	['v'] = 0, /* print version */
-	['w'] = 0, /* enable warnings */
-};
-
-void
-usage(void)
-{
-	fprint(2, "usage: %s [-ivw] [script] [arg ...]\n", argv0);
-	exits("usage");
-}
-
-int
-iscons(int fd)
-{
-	int n, c;
-	char buf[64];
-	
-	if(fd2path(fd, buf, sizeof buf) != 0)
-		sysfatal("fd2path: %r");
-	n = strlen(buf);
-	c = strlen("/dev/cons");
-	return n >= c && strcmp(buf + n - c, "/dev/cons") == 0;
-}
-
-void
-luaerror(lua_State *L)
-{
-	fprint(2, "%s: %s\n", argv0, lua_tostring(L, -1));
-	lua_pop(L, 1);
-}
-
-int
-pcallerror(lua_State *L)
-{
-	const char *m;
-	
-	m = lua_tostring(L, 1);
-	if(m == nil){
-		if(luaL_callmeta(L, 1, "__tostring") && lua_type(L, -1) == LUA_TSTRING)
-			return 1;
-		else
-			m = lua_pushfstring(L,
-				"(error object is a %s value)", luaL_typename(L, 1));
-	}
-	luaL_traceback(L, L, m, 1);
-	return 1;
-}
-
-int
-pcall(lua_State *L, int narg, int nres)
-{
-	int r, base;
-	
-	base = lua_gettop(L) - narg;
-	lua_pushcfunction(L, pcallerror);
-	lua_insert(L, base);
-	r = lua_pcall(L, narg, nres, base);
-	lua_remove(L, base);
-	return r;
-}
-
-int
-pushargs(lua_State *L)
-{
-	int i, n;
-	
-	/* Push the 'arg' array to stack */
-	if(lua_getglobal(L, "arg") != LUA_TTABLE)
-		luaL_error(L, "'arg' is not a table");
-	n = luaL_len(L, -1);
-	luaL_checkstack(L, n + 1, "too many arguments");
-	for(i = 1; i <= n; i++)
-		lua_rawgeti(L, -i, i);
-	lua_remove(L, -i);
-	return n;
-}
-
-int
-runrepl(lua_State *L)
-{
-	int r, narg;
-	char *ln;
-	Biobuf bin;
-	
-	if(Binit(&bin, 0, OREAD) == -1)
-		sysfatal("Binit: %r");
-	r = LUA_OK;
-	while(fprint(2, "> "), (ln = Brdstr(&bin, '\n', 1)) != nil){
-		if(luaL_loadstring(L, ln) != LUA_OK){
-			luaerror(L);
-			continue;
-		}
-		narg = pushargs(L);
-		if((r = pcall(L, narg, LUA_MULTRET)) != LUA_OK)
-			luaerror(L);
-	}
-	Bterm(&bin);
-	return r;
-}
-
-int
-runfile(lua_State *L, char *file)
-{
-	int narg, r;
-	
-	if((r = luaL_loadfile(L, file)) == LUA_OK){
-		narg = pushargs(L);
-		r = pcall(L, narg, LUA_MULTRET);
-	}
-	if(r != LUA_OK)
-		luaerror(L);
-	return r;
-}
-
-int
-luamain(lua_State *L)
-{
-	int argc, i;
-	char **argv, *file;
-	
-	argc = lua_tointeger(L, 1);
-	argv = lua_touserdata(L, 2);
-	file = argv[0];
-	
-	if(flag['w'])
-		lua_warning(L, "@on", 0);
-
-	/* Signal for libraries to ignore LUA_* env. vars */
-	lua_pushboolean(L, 1);
-	lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
-	luaL_openlibs(L);
-	
-	/* GC in generational mode */
-	lua_gc(L, LUA_GCGEN, 0, 0);
-	
-	/* Create global 'arg' table */
-	lua_createtable(L, argc, 0);
-	lua_pushstring(L, argv0);
-	lua_rawseti(L, -2, 0);
-	for(i = 1; i < argc; i++){
-		lua_pushstring(L, argv[i]);
-		lua_rawseti(L, -2, i);
-	}
-	lua_setglobal(L, "arg");
-	
-	if(file == nil){
-		file = "/fd/0";
-		if(flag['i'] && iscons(0))
-			file = nil;
-	}
-	if(file != nil)
-		runfile(L, file);
-	if(flag['i'])
-		runrepl(L);
-
-	lua_pushboolean(L, 1);
-	return 1;
-}
-
-void
-main(int argc, char *argv[])
-{
-	int r, v;
-	lua_State *L;
-	
-	ARGBEGIN{
-	case 'i': flag['i'] = 1; break;
-	case 'v': flag['v'] = 1; break;
-	case 'w': flag['w'] = 1; break;
-	default: usage();
-	}ARGEND;
-	if(flag['v']){
-		print("%s\n", LUA_COPYRIGHT);
-		exits(nil);
-	}
-
-	setfcr(getfcr() & ~(FPZDIV | FPOVFL | FPINVAL));
-	if((L = luaL_newstate()) == NULL)
-		sysfatal("out of memory");
-	lua_pushcfunction(L, luamain);
-	lua_pushinteger(L, argc);
-	lua_pushlightuserdata(L, argv);
-	r = lua_pcall(L, 2, 1, 0);
-	if(r != LUA_OK)
-		luaerror(L);
-	v = lua_toboolean(L, -1);
-	lua_close(L);
-	exits(r == LUA_OK && v == 1 ? nil : "errors");
-}
--- a/lua9.man
+++ /dev/null
@@ -1,132 +1,0 @@
-.TH LUA9 1
-.SH NAME
-lua9 \- Lua standalone for Plan 9
-.SH SYNOPSIS
-.B lua9
-.RB [ -ivw ]
-.RI [ script ]
-.RI [ args
-.IR ... ]
-.SH DESCRIPTION
-.PP
-.I Lua9
-is an interpreter for Lua as a standalone language.
-It runs Lua scripts and provides a basic REPL for
-interactive usage.
-.PP
-In addition to standard Lua libraries it is packed
-with several others which are likely to be useful
-for writing Plan 9 programs.
-This includes the library of bindings for the
-.I Plan 9
-C library
-and the
-.IR lpeg
-text processing library.
-Others are likely to be included in the future,
-guided by user demand.
-.SH USAGE
-.B Lua9
-runs in script mode by default, loading the
-.I script
-file if given, or loading the script from standard input
-if not.
-Given the
-.B -i
-option an interactive REPL is entered after the script
-finishes, or immediately if no script is given.
-.PP
-A script (a line in interactive mode) is compiled as
-a Lua chunk and called with variable number of arguments
-.I args
-given after the
-.I script
-on the command line.
-The arguments are also loaded into the global
-.IR arg 
-table, with
-.B arg[0]
-holding the executable (not script) name, and the elements
-.B arg[1]
-to
-.B arg[N]
-holding the respective arguments.
-.PP
-The
-.B -w
-option turns on the Lua warning system.
-.PP
-The
-.B -v
-option prints Lua version and exits.
-.SS MODULES
-The default
-.B package.path
-is set to:
-.PP
-.EX
-/sys/lib/lua/5.4/?.lua
-/sys/lib/lua/5.4/?/init.lua
-\&./?.lua
-\&./?/init.lua
-.EE
-.PP
-The
-.B package.cpath
-does nothing, as dynamically loaded C modules aren't supported.
-.SH EXAMPLES
-.PP
-Run a script with three arguments:
-.PP
-.EX
-; lua9 main.lua a b c
-.EE
-.PP
-Same as above, entering REPL after the script finishes:
-.PP
-.EX
-; lua9 -i main.lua a b c
-.EE
-.PP
-Run REPL with command line arguments:
-.PP
-.EX
-; lua9 -i /dev/null a b c
-.EE
-.PP
-An executable Lua program can be created as expected:
-.PP
-.EX
-; cat /bin/prog
-#!/bin/lua9
-io.write("hello world\\n")
-; chmod +x /bin/prog
-; prog
-.EE
-.SH SEE ALSO
-.PP
-Lua Reference Manual \- https://lua.org/manual/5.4
-.SH SOURCE
-.PP
-The interpreter and libraries making up the wider "Lua9"
-project can be found at:
-.PP
-.EE
-https://sr.ht/~kvik/lua9/
-.EX
-.SH BUGS
-.PP
-The interpreter interface and runtime environment resembles
-but is incompatible with the official
-.BR lua (1)
-version -- this is largely intentional to keep the code and
-runtime behaviour simple. Compatibility features might be
-accepted if they prove necessary in practice.
-.PP
-The Plan 9 libc bindings are WIP.
-.PP
-There's no way to pre-compile Lua code, as with
-.BR luac (1) .
-Patches accepted.
-.PP
-REPL is crude.  Patches accepted.
--- a/mkfile
+++ b/mkfile
@@ -1,8 +1,8 @@
 </$objtype/mkfile
 
-CFLAGS=-FTVw -p -Ishim -Ilua -Ilpeg -DLUA_USE_PLAN9
+CFLAGS=-FTVw -p -Ilua/shim -Ilua -Ilpeg -DLUA_USE_PLAN9
 
-TARG=$O.lua9
+TARG=$O.lu9
 BIN=/$objtype/bin
 MOD=/sys/lib/lua
 
@@ -11,41 +11,40 @@
 LIBS=\
 	lua/liblua.a.$O\
 	lpeg/liblpeg.a.$O\
-	shim/libshim.a.$O
+	p9/libp9.a.$O
 
 all:V: $TARG
 
 clone:V:
-	git/clone https://git.sr.ht/~kvik/lua9-lua lua
-	git/clone https://git.sr.ht/~kvik/lua9-lpeg lpeg
-	git/clone https://git.sr.ht/~kvik/lua9-shim shim
+	git/clone https://git.sr.ht/~kvik/lu9-lua lua
+	git/clone https://git.sr.ht/~kvik/lu9-lpeg lpeg
+	git/clone https://git.sr.ht/~kvik/lu9-p9 p9
 
 pull:V:
 	@{cd lua; git/pull}
 	@{cd lpeg; git/pull}
-	@{cd shim; git/pull}
+	@{cd p9; git/pull}
 
 install:V: $TARG
-	version=`{echo 'print(_VERSION)' | $TARG}
-	version=$version(2)
-	cp $TARG $BIN/lua9
-	cp $TARG $BIN/lua9-^$version
-	mkdir -p $MOD/$version
+	luav=`{$TARG -v}
+	cp $TARG $BIN/lu9
+	cp $TARG $BIN/lu9-^$luav
+	mkdir -p $MOD/$luav
 
 clean:V:
-	@{cd shim; mk clean}
 	@{cd lua; mk clean}
 	@{cd lpeg; mk clean}
+	@{cd p9; mk clean}
 	rm -f $TARG [$OS].out *.[$OS] *.a.[$OS]
 
-shim/libshim.a.$O:
-	@{cd shim; mk}
-
 lua/liblua.a.$O:
 	@{cd lua; mk}
 
 lpeg/liblpeg.a.$O:
 	@{cd lpeg; mk}
+	
+p9/libp9.a.$O:
+	@{cd p9; mk}
 
 $TARG: $OBJS $LIBS
 	$LD -o $TARG $prereq