Rewrite socket.try/protect in Lua

Move them into internal socket.except module. They are copied into
root socket module when it's required.
This commit is contained in:
mpeterv 2016-01-25 14:37:25 +03:00
parent bf13ec7fd4
commit 4e83ba271a
7 changed files with 73 additions and 163 deletions

View file

@ -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"

View file

@ -1,123 +0,0 @@
/*=========================================================================*\
* Simple exception support
* LuaSocket toolkit
\*=========================================================================*/
#include <stdio.h>
#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;
}

View file

@ -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

65
src/except.lua Normal file
View file

@ -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

View file

@ -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},

View file

@ -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

View file

@ -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)