summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmil Renner Berthing <esmil@mailme.dk>2011-02-24 01:25:19 +0100
committerEmil Renner Berthing <esmil@mailme.dk>2011-02-24 01:25:19 +0100
commit069af580c0cc7b877c42afdc433f3f8351aba9a4 (patch)
tree49dbeb3299fc4d32330c2176dd3af1309958f46e
parent81172aca43fb0d1c7cdc7d2c26acd7dc8d77b5d4 (diff)
downloadlem-069af580c0cc7b877c42afdc433f3f8351aba9a4.tar.gz
lem-069af580c0cc7b877c42afdc433f3f8351aba9a4.tar.xz
lem-069af580c0cc7b877c42afdc433f3f8351aba9a4.zip
added support for error handlers and implemented a REPL
-rw-r--r--Makefile19
-rw-r--r--PKGBUILD1
-rw-r--r--README.markdown2
-rwxr-xr-xlem-repl31
-rw-r--r--lem.c41
-rw-r--r--lem.h1
-rw-r--r--repl.lua117
-rw-r--r--utils.c18
8 files changed, 223 insertions, 7 deletions
diff --git a/Makefile b/Makefile
index 58c74e0..1625863 100644
--- a/Makefile
+++ b/Makefile
@@ -8,11 +8,12 @@ LUA_VERSION = 5.1
DESTDIR =
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
-LIBDIR = $(PREFIX)/lib/lua/$(LUA_VERSION)/lem
+LIBDIR = $(PREFIX)/lib/lua/$(LUA_VERSION)
INCDIR = $(PREFIX)/include
-programs = lem utils.so
headers = lem.h config.h macros.h lua/luaconf.h lua/lua.h lua/lauxlib.h libev/ev.h
+programs = lem utils.so
+scripts = repl.lua lem-repl
ifdef NDEBUG
DEFINES += -DNDEBUG
@@ -80,6 +81,10 @@ lem-install: lem bindir-install
$Mecho " INSTALL $<"
$O$(INSTALL) $< $(DESTDIR)$(BINDIR)/$<
+lem-repl-install: lem-repl bindir-install
+ $Mecho " INSTALL $<"
+ $O$(INSTALL) $< $(DESTDIR)$(BINDIR)/$<
+
incdir-install:
$Mecho " INSTALL -d $(INCDIR)/lem"
$O$(INSTALL) -d $(DESTDIR)$(INCDIR)/lem
@@ -94,13 +99,17 @@ lem.h-install: lem.h incdir-install
libdir-install:
$Mecho " INSTALL -d $(LIBDIR)"
- $O$(INSTALL) -d $(DESTDIR)$(LIBDIR)
+ $O$(INSTALL) -d $(DESTDIR)$(LIBDIR)/lem
%.so-install: %.so libdir-install
$Mecho " INSTALL $<"
- $O$(INSTALL) $< $(DESTDIR)$(LIBDIR)/$<
+ $O$(INSTALL) $< $(DESTDIR)$(LIBDIR)/lem/$<
+
+%.lua-install: %.lua libdir-install
+ $Mecho " INSTALL $<"
+ $O$(INSTALL) $< $(DESTDIR)$(LIBDIR)/lem/$<
-install: $(programs:%=%-install) $(headers:%=%-install)
+install: $(headers:%=%-install) $(programs:%=%-install) $(scripts:%=%-install)
clean:
rm -f config.h $(programs) *.o lua/*.o *.c~ *.h~
diff --git a/PKGBUILD b/PKGBUILD
index b2335bc..e2d8a52 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -8,6 +8,7 @@ arch=('i686' 'x86_64' 'armv5tel' 'armv7l')
url="https://github.com/esmil/lem"
license=('GPL')
depends=('glibc')
+optdepends=('lem-streams: for lem-repl')
source=()
build() {
diff --git a/README.markdown b/README.markdown
index fe47420..56851b9 100644
--- a/README.markdown
+++ b/README.markdown
@@ -154,7 +154,7 @@ License
-------
The Lua Event Machine is free software. It is distributed under the terms
-of the [GNU General Public License][gpl]
+of the [GNU General Public License][gpl].
[gpl]: http://www.fsf.org/licensing/licenses/gpl.html
diff --git a/lem-repl b/lem-repl
new file mode 100755
index 0000000..c796dbe
--- /dev/null
+++ b/lem-repl
@@ -0,0 +1,31 @@
+#!/usr/bin/env lem
+--
+-- This file is part of LEM, a Lua Event Machine.
+-- Copyright 2011 Emil Renner Berthing
+--
+-- LEM is free software: you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation, either version 3 of
+-- the License, or (at your option) any later version.
+--
+-- LEM is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with LEM. If not, see <http://www.gnu.org/licenses/>.
+--
+
+local streams = require 'lem.streams'
+local repl = require 'lem.repl'
+
+streams.stdout:write([[
+A Lua Event Machine 0.1 Copyright 2011 Emil Renner Berthing
+Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
+libev 4.03 Copyright (C)2007,2008,2009 Marc Alexander Lehmann
+]])
+
+repl.go('stdin', streams.stdin, streams.stdout)
+
+-- vim: syntax=lua ts=2 sw=2 noet:
diff --git a/lem.c b/lem.c
index 9fd3cc5..f0af489 100644
--- a/lem.c
+++ b/lem.c
@@ -134,6 +134,17 @@ lem_forgetthread(lua_State *T)
}
void
+lem_sethandler(lua_State *T)
+{
+ /* push T to L */
+ lua_pushthread(T);
+ lua_xmove(T, L, 1);
+ /* move handler to L */
+ lua_xmove(T, L, 1);
+ lua_rawset(L, LEM_THREADTABLE);
+}
+
+void
lem_queue(lua_State *T, int nargs)
{
struct lem_runqueue_slot *slot;
@@ -220,7 +231,35 @@ runqueue_pop(EV_P_ struct ev_idle *w, int revents)
case LUA_ERRRUN: /* runtime error */
lem_debug("thread errored");
+ /* push T to L */
+ lua_pushthread(T);
lua_xmove(T, L, 1);
+
+ /* push thread_table[T] */
+ lua_pushvalue(L, -1);
+ lua_rawget(L, LEM_THREADTABLE);
+ if (lua_type(L, -1) == LUA_TFUNCTION) {
+ lua_State *S = lem_newthread();
+
+ /* move error handler to S */
+ lua_xmove(L, S, 1);
+ /* move error message to S */
+ lua_xmove(T, S, 1);
+ /* queue thread */
+ lem_debug("queueing error handler: %s",
+ lua_tostring(S, -1));
+ lem_queue(S, 1);
+
+ /* thread_table[T] = nil */
+ lua_pushnil(L);
+ lua_rawset(L, LEM_THREADTABLE);
+ return;
+ }
+ lem_debug("no error handler");
+
+ /* move error message to L */
+ lua_xmove(T, L, 1);
+
rq.error = 1;
rq.status = EXIT_FAILURE;
ev_unloop(EV_A_ EVUNLOOP_ALL);
@@ -330,7 +369,7 @@ main(int argc, char *argv[])
if (rq.error) {
/* print error message */
- lem_log_error("%s", lua_tostring(L, lua_gettop(L)));
+ lem_log_error("%s", lua_tostring(L, -1));
}
/* shutdown Lua */
diff --git a/lem.h b/lem.h
index 9dd5b41..44f6934 100644
--- a/lem.h
+++ b/lem.h
@@ -32,6 +32,7 @@ extern struct ev_loop *lem_loop;
void *lem_xmalloc(size_t size);
lua_State *lem_newthread();
void lem_forgetthread(lua_State *T);
+void lem_sethandler(lua_State *T);
void lem_queue(lua_State *T, int nargs);
void lem_exit(int status);
diff --git a/repl.lua b/repl.lua
new file mode 100644
index 0000000..a3b799e
--- /dev/null
+++ b/repl.lua
@@ -0,0 +1,117 @@
+--
+-- This file is part of LEM, a Lua Event Machine.
+-- Copyright 2011 Emil Renner Berthing
+--
+-- LEM is free software: you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation, either version 3 of
+-- the License, or (at your option) any later version.
+--
+-- LEM is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with LEM. If not, see <http://www.gnu.org/licenses/>.
+--
+
+local utils = require 'lem.utils'
+
+local loadstring = loadstring
+local format = string.format
+local concat = table.concat
+local tostring = tostring
+local select = select
+
+local function repl(done, name, ins, outs)
+ if not outs then outs = ins end
+
+ local getcode, onreturn, onerror
+
+ name = '=' .. name
+
+ function getcode()
+ local res, err = outs:write('> ')
+ if not res then return done(nil, err) end
+
+ local line
+ line, err = ins:read('*l')
+ if not line then return done(nil, err) end
+
+ line = line:gsub('^=', 'return ')
+
+ while true do
+ res, err = loadstring(line, name)
+ if res then break end
+
+ if not err:match("'<eof>'") then
+ return onerror(err)
+ end
+
+ res, err = outs:write('>> ')
+ if not res then return done(nil, err) end
+
+ res, err = ins:read('*l')
+ if not res then return done(nil, err) end
+
+ line = line .. res
+ end
+
+ utils.sethandler(onerror)
+ return onreturn(res())
+ end
+
+ function onreturn(...)
+ utils.sethandler()
+ local args = select('#', ...)
+ if args == 0 then return getcode() end
+
+ local rstr
+ do
+ local t, ti = { ... }, nil
+ for i = 1, args - 1 do
+ t[i] = tostring(t[i])
+ end
+ t[args] = tostring(t[args])..'\n'
+
+ rstr = concat(t, '\t')
+ end
+
+ local ok, err = outs:write(rstr)
+ if not ok then return done(nil, err) end
+
+ return getcode()
+ end
+
+ function onerror(err)
+ local ok, err = outs:write(format("ERROR: %s\n", err))
+ if not ok then return done(nil, err) end
+
+ return getcode()
+ end
+
+ return getcode()
+end
+
+return {
+ wait = function(name, ins, outs)
+ local sleeper = utils.sleeper()
+ local function done(...)
+ return sleeper:wakeup(...)
+ end
+
+ utils.spawn(repl, done, name, ins, outs)
+
+ return sleeper:sleep()
+ end,
+
+ go = function(name, ins, outs)
+ local function done()
+ return outs:write('\n')
+ end
+ return repl(done, name, ins, outs)
+ end,
+}
+
+-- vim: syntax=lua ts=2 sw=2 noet:
diff --git a/utils.c b/utils.c
index 94536f1..d2ab740 100644
--- a/utils.c
+++ b/utils.c
@@ -215,6 +215,20 @@ yield_lua(lua_State *T)
}
static int
+sethandler_lua(lua_State *T)
+{
+ if (lua_gettop(T) > 0) {
+ luaL_checktype(T, 1, LUA_TFUNCTION);
+ lua_settop(T, 1);
+ } else
+ lua_pushboolean(T, 1);
+
+ lem_sethandler(T);
+
+ return 0;
+}
+
+static int
exit_lua(lua_State *T)
{
int status = (int)luaL_checknumber(T, 1);
@@ -265,6 +279,10 @@ int luaopen_lem_utils(lua_State *L)
lua_pushcfunction(L, yield_lua);
lua_setfield(L, 2, "yield");
+ /* set sethandler function */
+ lua_pushcfunction(L, sethandler_lua);
+ lua_setfield(L, 2, "sethandler");
+
/* set exit function */
lua_pushcfunction(L, exit_lua);
lua_setfield(L, 2, "exit");