From 4e83ba271a0d1a1e8993a413c9ce986adfee7594 Mon Sep 17 00:00:00 2001 From: mpeterv Date: Mon, 25 Jan 2016 14:37:25 +0300 Subject: [PATCH] Rewrite socket.try/protect in Lua Move them into internal socket.except module. They are copied into root socket module when it's required. --- luasocket-scm-0.rockspec | 3 +- src/except.c | 123 --------------------------------------- src/except.h | 33 ----------- src/except.lua | 65 +++++++++++++++++++++ src/luasocket.c | 2 - src/makefile | 7 +-- src/socket.lua | 3 + 7 files changed, 73 insertions(+), 163 deletions(-) delete mode 100644 src/except.c delete mode 100644 src/except.h create mode 100644 src/except.lua diff --git a/luasocket-scm-0.rockspec b/luasocket-scm-0.rockspec index 352a497..2d17b8f 100644 --- a/luasocket-scm-0.rockspec +++ b/luasocket-scm-0.rockspec @@ -50,7 +50,7 @@ local function make_plat(plat) } local modules = { ["socket.core"] = { - sources = { "src/luasocket.c", "src/timeout.c", "src/buffer.c", "src/io.c", "src/auxiliar.c", "src/options.c", "src/inet.c", "src/except.c", "src/select.c", "src/tcp.c", "src/udp.c", "src/compat.c" }, + sources = { "src/luasocket.c", "src/timeout.c", "src/buffer.c", "src/io.c", "src/auxiliar.c", "src/options.c", "src/inet.c", "src/select.c", "src/tcp.c", "src/udp.c", "src/compat.c" }, defines = defines[plat], incdir = "/src" }, @@ -65,6 +65,7 @@ local function make_plat(plat) ["socket.ftp"] = "src/ftp.lua", ["socket.headers"] = "src/headers.lua", ["socket.smtp"] = "src/smtp.lua", + ["socket.except"] = "src/except.lua", ltn12 = "src/ltn12.lua", socket = "src/socket.lua", mime = "src/mime.lua" diff --git a/src/except.c b/src/except.c deleted file mode 100644 index 261ac98..0000000 --- a/src/except.c +++ /dev/null @@ -1,123 +0,0 @@ -/*=========================================================================*\ -* Simple exception support -* LuaSocket toolkit -\*=========================================================================*/ -#include - -#include "lua.h" -#include "lauxlib.h" -#include "compat.h" - -#include "except.h" - -#if LUA_VERSION_NUM < 502 -#define lua_pcallk(L, na, nr, err, ctx, cont) \ - ((void)ctx,(void)cont,lua_pcall(L, na, nr, err)) -#endif - -#if LUA_VERSION_NUM < 503 -typedef int lua_KContext; -#endif - -/*=========================================================================*\ -* Internal function prototypes. -\*=========================================================================*/ -static int global_protect(lua_State *L); -static int global_newtry(lua_State *L); -static int protected_(lua_State *L); -static int finalize(lua_State *L); -static int do_nothing(lua_State *L); - -/* except functions */ -static luaL_Reg func[] = { - {"newtry", global_newtry}, - {"protect", global_protect}, - {NULL, NULL} -}; - -/*-------------------------------------------------------------------------*\ -* Try factory -\*-------------------------------------------------------------------------*/ -static void wrap(lua_State *L) { - lua_newtable(L); - lua_pushnumber(L, 1); - lua_pushvalue(L, -3); - lua_settable(L, -3); - lua_insert(L, -2); - lua_pop(L, 1); -} - -static int finalize(lua_State *L) { - if (!lua_toboolean(L, 1)) { - lua_pushvalue(L, lua_upvalueindex(1)); - lua_pcall(L, 0, 0, 0); - lua_settop(L, 2); - wrap(L); - lua_error(L); - return 0; - } else return lua_gettop(L); -} - -static int do_nothing(lua_State *L) { - (void) L; - return 0; -} - -static int global_newtry(lua_State *L) { - lua_settop(L, 1); - if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); - lua_pushcclosure(L, finalize, 1); - return 1; -} - -/*-------------------------------------------------------------------------*\ -* Protect factory -\*-------------------------------------------------------------------------*/ -static int unwrap(lua_State *L) { - if (lua_istable(L, -1)) { - lua_pushnumber(L, 1); - lua_gettable(L, -2); - lua_pushnil(L); - lua_insert(L, -2); - return 1; - } else return 0; -} - -static int protected_finish(lua_State *L, int status, lua_KContext ctx) { - (void)ctx; - if (status != 0 && status != LUA_YIELD) { - if (unwrap(L)) return 2; - else return lua_error(L); - } else return lua_gettop(L); -} - -#if LUA_VERSION_NUM == 502 -static int protected_cont(lua_State *L) { - int ctx = 0; - int status = lua_getctx(L, &ctx); - return protected_finish(L, status, ctx); -} -#else -#define protected_cont protected_finish -#endif - -static int protected_(lua_State *L) { - int status; - lua_pushvalue(L, lua_upvalueindex(1)); - lua_insert(L, 1); - status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont); - return protected_finish(L, status, 0); -} - -static int global_protect(lua_State *L) { - lua_pushcclosure(L, protected_, 1); - return 1; -} - -/*-------------------------------------------------------------------------*\ -* Init module -\*-------------------------------------------------------------------------*/ -int except_open(lua_State *L) { - luaL_setfuncs(L, func, 0); - return 0; -} diff --git a/src/except.h b/src/except.h deleted file mode 100644 index 1e7a245..0000000 --- a/src/except.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef EXCEPT_H -#define EXCEPT_H -/*=========================================================================*\ -* Exception control -* LuaSocket toolkit (but completely independent from other modules) -* -* This provides support for simple exceptions in Lua. During the -* development of the HTTP/FTP/SMTP support, it became aparent that -* error checking was taking a substantial amount of the coding. These -* function greatly simplify the task of checking errors. -* -* The main idea is that functions should return nil as its first return -* value when it finds an error, and return an error message (or value) -* following nil. In case of success, as long as the first value is not nil, -* the other values don't matter. -* -* The idea is to nest function calls with the "try" function. This function -* checks the first value, and calls "error" on the second if the first is -* nil. Otherwise, it returns all values it received. -* -* The protect function returns a new function that behaves exactly like the -* function it receives, but the new function doesn't throw exceptions: it -* returns nil followed by the error message instead. -* -* With these two function, it's easy to write functions that throw -* exceptions on error, but that don't interrupt the user script. -\*=========================================================================*/ - -#include "lua.h" - -int except_open(lua_State *L); - -#endif diff --git a/src/except.lua b/src/except.lua new file mode 100644 index 0000000..4b98caf --- /dev/null +++ b/src/except.lua @@ -0,0 +1,65 @@ +----------------------------------------------------------------------------- +-- Exception control +-- LuaSocket toolkit (but completely independent from other modules) +-- Author: Diego Nehab + +-- This provides support for simple exceptions in Lua. During the +-- development of the HTTP/FTP/SMTP support, it became aparent that +-- error checking was taking a substantial amount of the coding. These +-- function greatly simplify the task of checking errors. + +-- The main idea is that functions should return nil as its first return +-- value when it finds an error, and return an error message (or value) +-- following nil. In case of success, as long as the first value is not nil, +-- the other values don't matter. + +-- The idea is to nest function calls with the "try" function. This function +-- checks the first value, and calls "error" on the second if the first is +-- nil. Otherwise, it returns all values it received. + +-- The protect function returns a new function that behaves exactly like the +-- function it receives, but the new function doesn't throw exceptions: it +-- returns nil followed by the error message instead. + +-- With these two function, it's easy to write functions that throw +-- exceptions on error, but that don't interrupt the user script. +----------------------------------------------------------------------------- + +local base = _G +local _M = {} + +local function do_nothing() end + +function _M.newtry(finalizer) + if finalizer == nil then finalizer = do_nothing end + return function(...) + local ok, err = ... + if ok then + return ... + else + base.pcall(finalizer) + base.error({err}) + end + end +end + +local function handle_pcall_returns(ok, ...) + if ok then + return ... + else + local err = ... + if base.type(err) == "table" then + return nil, err[1] + else + base.error(err, 0) + end + end +end + +function _M.protect(func) + return function(...) + return handle_pcall_returns(base.pcall(func, ...)) + end +end + +return _M diff --git a/src/luasocket.c b/src/luasocket.c index 7d9c802..04875fb 100644 --- a/src/luasocket.c +++ b/src/luasocket.c @@ -24,7 +24,6 @@ \*=========================================================================*/ #include "luasocket.h" #include "auxiliar.h" -#include "except.h" #include "timeout.h" #include "buffer.h" #include "inet.h" @@ -44,7 +43,6 @@ static int base_open(lua_State *L); \*-------------------------------------------------------------------------*/ static const luaL_Reg mod[] = { {"auxiliar", auxiliar_open}, - {"except", except_open}, {"timeout", timeout_open}, {"buffer", buffer_open}, {"inet", inet_open}, diff --git a/src/makefile b/src/makefile index adf687f..d063f8a 100644 --- a/src/makefile +++ b/src/makefile @@ -283,7 +283,6 @@ SOCKET_OBJS= \ options.$(O) \ inet.$(O) \ $(SOCKET) \ - except.$(O) \ select.$(O) \ tcp.$(O) \ udp.$(O) @@ -328,7 +327,8 @@ TO_SOCKET_LDIR= \ tp.lua \ ftp.lua \ headers.lua \ - smtp.lua + smtp.lua \ + except.lua TO_TOP_LDIR= \ ltn12.lua \ @@ -410,10 +410,9 @@ clean: compat.$(O): compat.c compat.h auxiliar.$(O): auxiliar.c auxiliar.h buffer.$(O): buffer.c buffer.h io.h timeout.h -except.$(O): except.c except.h inet.$(O): inet.c inet.h socket.h io.h timeout.h usocket.h io.$(O): io.c io.h timeout.h -luasocket.$(O): luasocket.c luasocket.h auxiliar.h except.h \ +luasocket.$(O): luasocket.c luasocket.h auxiliar.h \ timeout.h buffer.h io.h inet.h socket.h usocket.h tcp.h \ udp.h select.h mime.$(O): mime.c mime.h diff --git a/src/socket.lua b/src/socket.lua index d1c0b16..d440caa 100644 --- a/src/socket.lua +++ b/src/socket.lua @@ -10,6 +10,7 @@ local base = _G local string = require("string") local math = require("math") local socket = require("socket.core") +local except = require("socket.except") local _M = socket @@ -53,7 +54,9 @@ function _M.bind(host, port, backlog) return nil, err end +_M.newtry = except.newtry _M.try = _M.newtry() +_M.protect = except.protect function _M.choose(table) return function(name, opt1, opt2)