From 069af580c0cc7b877c42afdc433f3f8351aba9a4 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Thu, 24 Feb 2011 01:25:19 +0100 Subject: added support for error handlers and implemented a REPL --- Makefile | 19 ++++++--- PKGBUILD | 1 + README.markdown | 2 +- lem-repl | 31 +++++++++++++++ lem.c | 41 +++++++++++++++++++- lem.h | 1 + repl.lua | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ utils.c | 18 +++++++++ 8 files changed, 223 insertions(+), 7 deletions(-) create mode 100755 lem-repl create mode 100644 repl.lua 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 . +-- + +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 @@ -133,6 +133,17 @@ lem_forgetthread(lua_State *T) lua_rawset(L, LEM_THREADTABLE); } +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) { @@ -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 . +-- + +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("''") 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 @@ -214,6 +214,20 @@ yield_lua(lua_State *T) return lua_yield(T, 0); } +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) { @@ -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"); -- cgit v1.2.1