diff --git a/.gitignore b/.gitignore
index edf6645..a0f490b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,7 @@
*.i*86
*.x86_64
*.hex
+
+#
+*.exp
+*.d
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..1c89bb9
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,36 @@
+language: c
+
+env:
+ global:
+ - LUAROCKS=2.2.0
+ matrix:
+ - LUA=lua5.1
+ - LUA=lua5.2
+ - LUA=luajit
+
+services:
+ - memcached
+
+branches:
+ only:
+ - master
+
+before_install:
+ - bash .travis/setup_lua.sh
+ - sudo luarocks install lunitx
+ - sudo pip install cpp-coveralls
+
+install:
+ - sudo luarocks make rockspecs/try-scm-0.rockspec CFLAGS="-O2 -fPIC -ftest-coverage -fprofile-arcs" LIBFLAG="-shared --coverage"
+
+script:
+ - cd test
+ - lunit.sh test.lua
+
+after_success:
+ - coveralls -b .. -r ..
+
+notifications:
+ email:
+ on_success: change
+ on_failure: always
diff --git a/.travis/platform.sh b/.travis/platform.sh
new file mode 100644
index 0000000..4a3af0d
--- /dev/null
+++ b/.travis/platform.sh
@@ -0,0 +1,15 @@
+if [ -z "$PLATFORM" ]; then
+ PLATFORM=$TRAVIS_OS_NAME;
+fi
+
+if [ "$PLATFORM" == "osx" ]; then
+ PLATFORM="macosx";
+fi
+
+if [ -z "$PLATFORM" ]; then
+ if [ "$(uname)" == "Linux" ]; then
+ PLATFORM="linux";
+ else
+ PLATFORM="macosx";
+ fi;
+fi
diff --git a/.travis/setup_lua.sh b/.travis/setup_lua.sh
new file mode 100644
index 0000000..c44b79a
--- /dev/null
+++ b/.travis/setup_lua.sh
@@ -0,0 +1,96 @@
+#! /bin/bash
+
+# A script for setting up environment for travis-ci testing.
+# Sets up Lua and Luarocks.
+# LUA must be "lua5.1", "lua5.2" or "luajit".
+# luajit2.0 - master v2.0
+# luajit2.1 - master v2.1
+
+LUAJIT_BASE="LuaJIT-2.0.3"
+
+source .travis/platform.sh
+
+LUAJIT="no"
+
+if [ "$PLATFORM" == "macosx" ]; then
+ if [ "$LUA" == "luajit" ]; then
+ LUAJIT="yes";
+ fi
+ if [ "$LUA" == "luajit2.0" ]; then
+ LUAJIT="yes";
+ fi
+ if [ "$LUA" == "luajit2.1" ]; then
+ LUAJIT="yes";
+ fi;
+elif [ "$(expr substr $LUA 1 6)" == "luajit" ]; then
+ LUAJIT="yes";
+fi
+
+if [ "$LUAJIT" == "yes" ]; then
+
+ if [ "$LUA" == "luajit" ]; then
+ curl http://luajit.org/download/$LUAJIT_BASE.tar.gz | tar xz;
+ else
+ git clone http://luajit.org/git/luajit-2.0.git $LUAJIT_BASE;
+ fi
+
+ cd $LUAJIT_BASE
+
+ if [ "$LUA" == "luajit2.1" ]; then
+ git checkout v2.1;
+ fi
+
+ make && sudo make install
+
+ if [ "$LUA" == "luajit2.1" ]; then
+ sudo ln -s /usr/local/bin/luajit-2.1.0-alpha /usr/local/bin/luajit
+ sudo ln -s /usr/local/bin/luajit /usr/local/bin/lua;
+ else
+ sudo ln -s /usr/local/bin/luajit /usr/local/bin/lua;
+ fi;
+
+else
+ if [ "$LUA" == "lua5.1" ]; then
+ curl http://www.lua.org/ftp/lua-5.1.5.tar.gz | tar xz
+ cd lua-5.1.5;
+ elif [ "$LUA" == "lua5.2" ]; then
+ curl http://www.lua.org/ftp/lua-5.2.3.tar.gz | tar xz
+ cd lua-5.2.3;
+ fi
+ sudo make $PLATFORM install;
+fi
+
+cd $TRAVIS_BUILD_DIR;
+
+LUAROCKS_BASE=luarocks-$LUAROCKS
+
+# curl http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz | tar xz
+
+git clone https://github.com/keplerproject/luarocks.git $LUAROCKS_BASE
+cd $LUAROCKS_BASE
+
+git checkout v$LUAROCKS
+
+if [ "$LUA" == "luajit" ]; then
+ ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.0;
+elif [ "$LUA" == "luajit2.0" ]; then
+ ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.0;
+elif [ "$LUA" == "luajit2.1" ]; then
+ ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.1;
+else
+ ./configure;
+fi
+
+make build && sudo make install
+
+cd $TRAVIS_BUILD_DIR
+
+rm -rf $LUAROCKS_BASE
+
+if [ "$LUAJIT" == "yes" ]; then
+ rm -rf $LUAJIT_BASE;
+elif [ "$LUA" == "lua5.1" ]; then
+ rm -rf lua-5.1.5;
+elif [ "$LUA" == "lua5.2" ]; then
+ rm -rf lua-5.2.3;
+fi
diff --git a/lakeconfig.lua b/lakeconfig.lua
new file mode 100644
index 0000000..0125d13
--- /dev/null
+++ b/lakeconfig.lua
@@ -0,0 +1,260 @@
+local io = require "io"
+io.stdout:setvbuf"no"
+io.stderr:setvbuf"no"
+
+function vc_version()
+ local VER = lake.compiler_version()
+ MSVC_VER = ({
+ [15] = '9';
+ [16] = '10';
+ })[VER.MAJOR] or ''
+ return MSVC_VER
+end
+
+if not L then
+
+local function arkey(t)
+ assert(type(t) == 'table')
+ local keys = {}
+ for k in pairs(t) do
+ assert(type(k) == 'number')
+ table.insert(keys, k)
+ end
+ table.sort(keys)
+ return keys
+end
+
+local function ikeys(t)
+ local keys = arkey(t)
+ local i = 0
+ return function()
+ i = i + 1
+ local k = keys[i]
+ if k == nil then return end
+ return k, t[k]
+ end
+end
+
+local function expand(arr, t)
+ if t == nil then return arr end
+
+ if type(t) ~= 'table' then
+ table.insert(arr, t)
+ return arr
+ end
+
+ for _, v in ikeys(t) do
+ expand(arr, v)
+ end
+
+ return arr
+end
+
+function L(...)
+ return expand({}, {...})
+end
+
+end
+
+J = J or path.join
+
+IF = IF or lake.choose or choose
+
+DIR_SEP = package.config:sub(1,1)
+
+function prequire(...)
+ local ok, mod = pcall(require, ...)
+ if ok then return mod end
+end
+
+function clone(t, o)
+ o = o or {}
+ for k, v in pairs(t) do
+ if o[k] == nil then o[k] = v end
+ end
+ return o
+end
+
+function each_join(dir, list)
+ for i, v in ipairs(list) do
+ list[i] = path.join(dir, v)
+ end
+ return list
+end
+
+function run(file, cwd)
+ print()
+ print("run " .. file)
+ if not TESTING then
+ if cwd then lake.chdir(cwd) end
+ local status, code = utils.execute( LUA_RUNNER .. ' ' .. file )
+ if cwd then lake.chdir("<") end
+ print()
+ return status, code
+ end
+ return true, 0
+end
+
+function exec(file, cwd)
+ print()
+ print("exec " .. file)
+ if not TESTING then
+ if cwd then lake.chdir(cwd) end
+ local status, code = utils.execute( file )
+ if cwd then lake.chdir("<") end
+ print()
+ return status, code
+ end
+ return true, 0
+end
+
+local TESTS = {}
+
+function run_test(name, params)
+ local test_dir = TESTDIR or J(ROOT, 'test')
+ local cmd = J(test_dir, name)
+ if params then cmd = cmd .. ' ' .. params end
+ local ok = run(cmd, test_dir)
+
+ table.insert(TESTS, {cmd = cmd, result = ok})
+
+ print("TEST " .. name .. (ok and ' - pass!' or ' - fail!'))
+end
+
+function exec_test(name, params)
+ local test_dir = TESTDIR or J(ROOT, 'test')
+ local cmd = J(test_dir, name)
+ if params then cmd = cmd .. ' ' .. params end
+ local ok = exec(cmd, test_dir)
+
+ table.insert(TESTS, {cmd = cmd, result = ok})
+
+ print("TEST " .. name .. (ok and ' - pass!' or ' - fail!'))
+end
+
+function test_summary()
+ local ok = true
+ print("")
+ print("------------------------------------")
+ print("Number of tests:", #TESTS)
+ for _, t in ipairs(TESTS) do
+ ok = ok and t.result
+ print((t.result and ' Pass' or ' Fail') .. " - TEST " .. t.cmd)
+ end
+ print("------------------------------------")
+ print("")
+ return ok
+end
+
+--[[spawn]] if WINDOWS then
+ function spawn(file, cwd)
+ local winapi = prequire "winapi"
+ if not winapi then
+ quit('needs winapi for spawn!')
+ return false
+ end
+
+ print("spawn " .. file)
+ if not TESTING then
+ if cwd then lake.chdir(cwd) end
+ assert(winapi.shell_exec(nil, LUA_RUNNER, file, cwd))
+ if cwd then lake.chdir("<") end
+ print()
+ end
+ return true
+ end
+else
+ function spawn(file, cwd)
+ print("spawn " .. file)
+ if not TESTING then
+ assert(run(file .. ' &', cwd))
+ end
+ return true
+ end
+end
+
+function as_bool(v,d)
+ if v == nil then return not not d end
+ local n = tonumber(v)
+ if n == 0 then return false end
+ if n then return true end
+ return false
+end
+
+--- set global variables
+-- LUA_NEED
+-- LUA_DIR
+-- LUA_RUNNER
+-- ROOT
+-- LUADIR
+-- LIBDIR
+-- TESTDIR
+-- DOCDIR
+-- DYNAMIC
+function INITLAKEFILE()
+ if LUA_VER == '5.3' then
+ LUA_NEED = 'lua53'
+ LUA_DIR = ENV.LUA_DIR_5_3 or ENV.LUA_DIR
+ LUA_RUNNER = LUA_RUNNER or 'lua53'
+ elseif LUA_VER == '5.2' then
+ LUA_NEED = 'lua52'
+ LUA_DIR = ENV.LUA_DIR_5_2 or ENV.LUA_DIR
+ LUA_RUNNER = LUA_RUNNER or 'lua52'
+ elseif LUA_VER == '5.1' then
+ LUA_NEED = 'lua51'
+ LUA_DIR = ENV.LUA_DIR
+ LUA_RUNNER = LUA_RUNNER or 'lua'
+ else
+ LUA_NEED = 'lua'
+ LUA_DIR = ENV.LUA_DIR
+ LUA_RUNNER = LUA_RUNNER or 'lua'
+ end
+ ROOT = ROOT or J( LUA_DIR, 'libs', PROJECT )
+ LUADIR = LUADIR or J( ROOT, 'share' )
+ LIBDIR = LIBDIR or J( ROOT, 'share' )
+ TESTDIR = TESTDIR or J( ROOT, 'test' )
+ DOCDIR = DOCDIR or J( ROOT, 'doc' )
+ DYNAMIC = as_bool(DYNAMIC, false)
+end
+
+-----------------------
+-- needs --
+-----------------------
+
+lake.define_need('lua53', function()
+ return {
+ incdir = J(ENV.LUA_DIR_5_3, 'include');
+ libdir = J(ENV.LUA_DIR_5_3, 'lib');
+ libs = {'lua53'};
+ }
+end)
+
+lake.define_need('lua52', function()
+ return {
+ incdir = J(ENV.LUA_DIR_5_2, 'include');
+ libdir = J(ENV.LUA_DIR_5_2, 'lib');
+ libs = {'lua52'};
+ }
+end)
+
+lake.define_need('lua51', function()
+ return {
+ incdir = J(ENV.LUA_DIR, 'include');
+ libdir = J(ENV.LUA_DIR, 'lib');
+ libs = {'lua5.1'};
+ }
+end)
+
+local UV_DIR = UV_DIR or ENV.UV_DIR or J(ENV.CPPLIB_DIR, 'uv')
+
+lake.define_need('libuv', function()
+ return {
+ incdir = J(UV_DIR, 'include');
+ libdir = J(UV_DIR, 'lib');
+ libs = {'libuv'};
+ }
+end)
+
+lake.define_need('winsock2', function()
+ return {libs = {"ws2_32"}}
+end)
\ No newline at end of file
diff --git a/lakefile b/lakefile
new file mode 100644
index 0000000..3e5b31f
--- /dev/null
+++ b/lakefile
@@ -0,0 +1,33 @@
+PROJECT = 'try'
+
+INITLAKEFILE()
+
+DEFINES = L{DEFINES,
+ IF(WINDOWS, 'DLL_EXPORT', '');
+}
+
+try = c.shared{'try',
+ base = 'src',
+ src = '*.c',
+ needs = {LUA_NEED},
+ defines = DEFINES,
+ dynamic = DYNAMIC,
+ strip = true,
+}
+
+target('build', try)
+
+install = target('install', {
+ file.group{odir=LIBDIR; src = try };
+ -- file.group{odir=LIBDIR; src = J("src", "lua") ; recurse = true };
+ -- file.group{odir=J(ROOT, 'examples'); src = 'examples'; recurse = true };
+ file.group{odir=TESTDIR; src = 'test'; recurse = true };
+})
+
+target('test', install, function()
+ run_test('test.lua')
+
+ if not test_summary() then
+ quit("test fail")
+ end
+end)
\ No newline at end of file
diff --git a/msvc/try.sln b/msvc/try.sln
new file mode 100644
index 0000000..0c343ae
--- /dev/null
+++ b/msvc/try.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "try", "try.vcproj", "{C9D035B7-BBF9-4D7A-960F-B8ED2CB6FF8E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C9D035B7-BBF9-4D7A-960F-B8ED2CB6FF8E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C9D035B7-BBF9-4D7A-960F-B8ED2CB6FF8E}.Debug|Win32.Build.0 = Debug|Win32
+ {C9D035B7-BBF9-4D7A-960F-B8ED2CB6FF8E}.Release|Win32.ActiveCfg = Release|Win32
+ {C9D035B7-BBF9-4D7A-960F-B8ED2CB6FF8E}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/msvc/try.vcproj b/msvc/try.vcproj
new file mode 100644
index 0000000..f8ff092
--- /dev/null
+++ b/msvc/try.vcproj
@@ -0,0 +1,196 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rockspecs/try-scm-0.rockspec b/rockspecs/try-scm-0.rockspec
new file mode 100644
index 0000000..1694465
--- /dev/null
+++ b/rockspecs/try-scm-0.rockspec
@@ -0,0 +1,32 @@
+package = "try"
+version = "scm-0"
+
+source = {
+ url = "https://github.com/moteus/lua-try/archive/master.zip",
+ dir = "lua-try-master",
+}
+
+description = {
+ summary = "Simple exception support based on LuaSocket",
+ homepage = "https://github.com/moteus/lua-try",
+ license = "MIT/X11",
+ maintainer = "Alexey Melnichuk",
+ detailed = [[
+ ]],
+}
+
+dependencies = {
+ "lua >= 5.1, < 5.4"
+}
+
+build = {
+ copy_directories = {'test'},
+
+ type = "builtin",
+
+ modules = {
+ try = {
+ sources = { "src/try.c" },
+ },
+ }
+}
diff --git a/src/try.c b/src/try.c
new file mode 100644
index 0000000..09fdfd0
--- /dev/null
+++ b/src/try.c
@@ -0,0 +1,196 @@
+/*=========================================================================*\
+* Simple exception support
+* LuaSocket toolkit
+\*=========================================================================*/
+#include
+
+#include "lua.h"
+#include "lauxlib.h"
+
+/*export*/
+#ifdef _WIN32
+# define EXPORT_API __declspec(dllexport)
+#else
+# define EXPORT_API LUALIB_API
+#endif
+
+static const char *TRY_ERROR_IDX = "Dummy";
+static const char *TRY_ERROR_NIL = "NIL";
+
+
+/*=========================================================================*\
+* Internal function prototypes.
+\*=========================================================================*/
+static int try_new_assert(lua_State *L);
+static int try_new_protect(lua_State *L);
+
+/* except functions */
+static luaL_Reg func[] = {
+ {"new", try_new_assert},
+ {"protect", try_new_protect},
+ {NULL, NULL}
+};
+
+#if LUA_VERSION_NUM < 502
+
+#define lua_absindex(L, i) (((i)>0)?(i):((i)<=LUA_REGISTRYINDEX?(i):(lua_gettop(L)+(i)+1)))
+
+void lua_rawgetp(lua_State *L, int index, const void *p){
+ index = lua_absindex(L, index);
+ lua_pushlightuserdata(L, (void *)p);
+ lua_rawget(L, index);
+}
+
+void lua_rawsetp (lua_State *L, int index, const void *p){
+ index = lua_absindex(L, index);
+ lua_pushlightuserdata(L, (void *)p);
+ lua_insert(L, -2);
+ lua_rawset(L, index);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*\
+* Error wrapper
+\*-------------------------------------------------------------------------*/
+static int try_check_error(lua_State *L) {
+ if(lua_istable(L, -1)){
+ lua_rawgetp(L, -1, TRY_ERROR_IDX);
+
+ if(lua_isnil(L, -1)){ /*not try error*/
+ lua_pop(L, 1);
+ return 0;
+ }
+
+ if(lua_touserdata(L, -1) == TRY_ERROR_NIL){ /*no value*/
+ lua_pop(L, 1);
+ lua_pushnil(L);
+ }
+
+ lua_pushnil(L);
+ lua_insert(L, -2);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int try_error(lua_State *L){
+ lua_newtable(L);
+ if(lua_isnil(L, -2)){
+ lua_pushlightuserdata(L, (void*)TRY_ERROR_NIL);
+ }
+ else{
+ lua_pushvalue(L, -2);
+ }
+ lua_rawsetp(L, -2, TRY_ERROR_IDX);
+ return lua_error(L);
+}
+
+/*-------------------------------------------------------------------------*\
+* Try factory
+\*-------------------------------------------------------------------------*/
+
+static int try_assert(lua_State *L) {
+ if(!lua_toboolean(L, 1)){
+ /* call finalizer */
+ if(!lua_isnil(L, lua_upvalueindex(1))){
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_pcall(L, 0, 0, 0);
+ }
+ lua_settop(L, 2);
+
+ return try_error(L);
+ }
+ return lua_gettop(L);
+}
+
+static int try_new_assert(lua_State *L) {
+ lua_settop(L, 1);
+ lua_pushcclosure(L, try_assert, 1);
+ return 1;
+}
+
+/*-------------------------------------------------------------------------*\
+* Protect factory
+\*-------------------------------------------------------------------------*/
+
+#if LUA_VERSION_NUM < 503
+
+typedef int lua_KContext;
+
+#endif
+
+#if LUA_VERSION_NUM <= 501
+#ifndef LUA_OK
+#define LUA_OK 0
+#endif
+#endif
+
+static int try_protected(lua_State *L);
+
+static int try_protected_k(lua_State *L, int status, lua_KContext ctx){
+ if(status == LUA_OK){
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_insert(L, 1);
+
+ status =
+#if LUA_VERSION_NUM <= 501
+ lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0);
+#else
+ lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0,
+#if LUA_VERSION_NUM == 502
+ try_protected
+#else
+ try_protected_k
+#endif
+ );
+#endif
+ if(status == LUA_OK) status = LUA_YIELD;
+ }
+
+ if(status == LUA_YIELD){
+ return lua_gettop(L);
+ }
+
+ if(status == LUA_ERRRUN){
+ if(try_check_error(L)) return 2;
+ }
+
+ lua_error(L);
+ return 0;
+}
+
+static int try_protected(lua_State *L){
+ int status;
+ lua_KContext ctx;
+
+#if LUA_VERSION_NUM == 502
+ status = lua_getctx(L, &ctx);
+#else
+ status = LUA_OK;
+ ctx = 0;
+#endif
+
+ return try_protected_k(L, status, ctx);
+}
+
+static int try_new_protect(lua_State *L){
+ lua_pushcclosure(L, try_protected, 1);
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------*\
+* Init module
+\*-------------------------------------------------------------------------*/
+EXPORT_API int luaopen_try(lua_State *L) {
+ lua_newtable(L);
+#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
+ luaL_setfuncs(L, func, 0);
+#else
+ luaL_openlib(L, NULL, func, 0);
+#endif
+ return 1;
+}
diff --git a/test/test.lua b/test/test.lua
new file mode 100644
index 0000000..d6c7f0b
--- /dev/null
+++ b/test/test.lua
@@ -0,0 +1,167 @@
+local lunit = lunit
+
+local RUN = lunit and function()end or function ()
+ local res = lunit.run()
+ if res.errors + res.failed > 0 then
+ os.exit(-1)
+ end
+ return os.exit(0)
+end
+
+lunit = require "lunit"
+
+local TEST_CASE = assert(lunit.TEST_CASE)
+local skip = lunit.skip or function() end
+
+local try = require "try"
+local coroutine = require "coroutine"
+
+local function nreturn(...)
+ return select("#", ...), ...
+end
+
+local pcall, error = pcall, error
+
+local IS_LUA_51 = (_VERSION == "Lua 5.1")
+
+local ENABLE = true
+
+local _ENV = TEST_CASE'try.basic' if ENABLE then
+
+local it = setmetatable(_ENV or _M, {__call = function(self, describe, fn)
+ self["test " .. describe] = fn
+end})
+
+function setup() end
+
+function teardown() end
+
+it("return value", function()
+ local fn = assert_function(try.protect(function()
+ return 1, nil, 3, nil
+ end))
+ local n, a, b, c, d = nreturn(fn())
+ assert_equal(4, n)
+ assert_equal(1, a)
+ assert_nil(b)
+ assert_equal(3, c)
+ assert_nil(d)
+end)
+
+it("call finalizer", function()
+ local n = 0
+ local EVALUE = 'some value'
+ local check = try.new(function() n = n + 1 end)
+
+ local fn = assert_function(try.protect(function()
+ check(nil, EVALUE)
+ end))
+
+ local _, b = assert_nil(fn())
+ assert_equal(EVALUE, b)
+ assert_equal(1, n)
+end)
+
+it("call finalizer and return nil", function()
+ local n = 0
+ local EVALUE = nil
+ local check = try.new(function() n = n + 1 end)
+
+ local fn = assert_function(try.protect(function()
+ check(nil, EVALUE)
+ end))
+
+ local _, b = assert_nil(fn())
+ assert_equal(EVALUE, b)
+ assert_equal(1, n)
+end)
+
+it("raise error", function()
+ local n = 0
+ local EVALUE = "some value"
+ local check = try.new(function() n = n + 1 end)
+
+ local fn = assert_function(try.protect(function()
+ error(EVALUE)
+ end))
+
+ local ok, err = pcall(fn)
+ assert_false(ok)
+ assert_match(EVALUE, err)
+end)
+
+it("raise error and return table", function()
+ local n = 0
+ local EVALUE = {"some value"}
+ local check = try.new(function() n = n + 1 end)
+
+ local fn = assert_function(try.protect(function()
+ error(EVALUE)
+ end))
+
+ local ok, err = pcall(fn)
+ assert_false(ok)
+ assert_equal(EVALUE, err)
+end)
+
+end
+
+local _ENV = TEST_CASE'try.coro' if ENABLE and not IS_LUA_51 then
+
+local it = setmetatable(_ENV or _M, {__call = function(self, describe, fn)
+ self["test " .. describe] = fn
+end})
+
+function setup() end
+
+function teardown() end
+
+it("return value", function()
+ local co = coroutine.create(try.protect(function(...)
+ return ...
+ end))
+
+ local n, ok, a, b, c, d = nreturn(coroutine.resume(co, 1, nil, 3, nil))
+ assert_equal(5, n)
+ assert_true(ok)
+ assert_equal(1, a)
+ assert_nil(b)
+ assert_equal(3, c)
+ assert_nil(d)
+end)
+
+it("yeild inside protect", function()
+ local co = coroutine.create(try.protect(function(...)
+ return coroutine.yield(...)
+ end))
+
+ local n, ok, a, b, c, d = nreturn(coroutine.resume(co, 1, nil, 3, nil))
+ assert_equal(5, n)
+ assert_true(ok)
+ assert_equal(1, a)
+ assert_nil(b)
+ assert_equal(3, c)
+ assert_nil(d)
+
+ assert_true(coroutine.resume(co))
+end)
+
+it("check inside coroutine", function()
+ local n = 0
+ local EVALUE = 'some value'
+ local check = try.new(function() n = n + 1 end)
+
+ local co = coroutine.create(try.protect(function(...)
+ check(nil, EVALUE)
+ end))
+
+ local n, ok, a, b = nreturn(coroutine.resume(co, 1, nil, 3, nil))
+ assert_equal(3, n)
+ assert_true(ok)
+ assert_nil(a)
+ assert_equal(EVALUE, b)
+end)
+
+end
+
+RUN()