|
@@ -177,13 +177,19 @@ print"testing to-be-closed variables"
|
|
|
|
|
|
local function stack(n) n = ((n == 0) or stack(n - 1)) end
|
|
|
|
|
|
+local function func2close (f)
|
|
|
+ return setmetatable({}, {__close = f})
|
|
|
+end
|
|
|
+
|
|
|
|
|
|
do
|
|
|
local a = {}
|
|
|
do
|
|
|
local *toclose x = setmetatable({"x"}, {__close = function (self)
|
|
|
a[#a + 1] = self[1] end})
|
|
|
- local *toclose y = function (x) assert(x == nil); a[#a + 1] = "y" end
|
|
|
+ local *toclose y = func2close(function (self, err)
|
|
|
+ assert(err == nil); a[#a + 1] = "y"
|
|
|
+ end)
|
|
|
a[#a + 1] = "in"
|
|
|
end
|
|
|
a[#a + 1] = "out"
|
|
@@ -193,7 +199,7 @@ end
|
|
|
do
|
|
|
local X = false
|
|
|
|
|
|
- local function closescope () stack(10); X = true end
|
|
|
+ local closescope = func2close(function () stack(10); X = true end)
|
|
|
|
|
|
-- closing functions do not corrupt returning values
|
|
|
local function foo (x)
|
|
@@ -228,13 +234,13 @@ do
|
|
|
-- calls cannot be tail in the scope of to-be-closed variables
|
|
|
local X, Y
|
|
|
local function foo ()
|
|
|
- local *toclose _ = function () Y = 10 end
|
|
|
+ local *toclose _ = func2close(function () Y = 10 end)
|
|
|
assert(X == true and Y == nil) -- 'X' not closed yet
|
|
|
return 1,2,3
|
|
|
end
|
|
|
|
|
|
local function bar ()
|
|
|
- local *toclose _ = function () X = false end
|
|
|
+ local *toclose _ = func2close(function () X = false end)
|
|
|
X = true
|
|
|
do
|
|
|
return foo() -- not a tail call!
|
|
@@ -249,11 +255,15 @@ end
|
|
|
do -- errors in __close
|
|
|
local log = {}
|
|
|
local function foo (err)
|
|
|
- local *toclose x = function (msg) log[#log + 1] = msg; error(1) end
|
|
|
- local *toclose x1 = function (msg) log[#log + 1] = msg; end
|
|
|
- local *toclose gc = function () collectgarbage() end
|
|
|
- local *toclose y = function (msg) log[#log + 1] = msg; error(2) end
|
|
|
- local *toclose z = function (msg) log[#log + 1] = msg or 10; error(3) end
|
|
|
+ local *toclose x =
|
|
|
+ func2close(function (self, msg) log[#log + 1] = msg; error(1) end)
|
|
|
+ local *toclose x1 =
|
|
|
+ func2close(function (self, msg) log[#log + 1] = msg; end)
|
|
|
+ local *toclose gc = func2close(function () collectgarbage() end)
|
|
|
+ local *toclose y =
|
|
|
+ func2close(function (self, msg) log[#log + 1] = msg; error(2) end)
|
|
|
+ local *toclose z =
|
|
|
+ func2close(function (self, msg) log[#log + 1] = msg or 10; error(3) end)
|
|
|
if err then error(4) end
|
|
|
end
|
|
|
local stat, msg = pcall(foo, false)
|
|
@@ -282,7 +292,7 @@ do
|
|
|
-- with other errors, non-closable values are ignored
|
|
|
local function foo ()
|
|
|
local *toclose x = 34
|
|
|
- local *toclose y = function () error(32) end
|
|
|
+ local *toclose y = func2close(function () error(32) end)
|
|
|
end
|
|
|
local stat, msg = pcall(foo)
|
|
|
assert(not stat and msg == 32)
|
|
@@ -294,7 +304,7 @@ if rawget(_G, "T") then
|
|
|
|
|
|
-- memory error inside closing function
|
|
|
local function foo ()
|
|
|
- local *toclose y = function () T.alloccount() end
|
|
|
+ local *toclose y = func2close(function () T.alloccount() end)
|
|
|
local *toclose x = setmetatable({}, {__close = function ()
|
|
|
T.alloccount(0); local x = {} -- force a memory error
|
|
|
end})
|
|
@@ -308,12 +318,12 @@ if rawget(_G, "T") then
|
|
|
local _, msg = pcall(foo)
|
|
|
assert(msg == "not enough memory")
|
|
|
|
|
|
- local function close (msg)
|
|
|
+ local close = func2close(function (self, msg)
|
|
|
T.alloccount()
|
|
|
assert(msg == "not enough memory")
|
|
|
- end
|
|
|
+ end)
|
|
|
|
|
|
- -- set a memory limit and return a closing function to remove the limit
|
|
|
+ -- set a memory limit and return a closing object to remove the limit
|
|
|
local function enter (count)
|
|
|
stack(10) -- reserve some stack space
|
|
|
T.alloccount(count)
|
|
@@ -336,13 +346,13 @@ if rawget(_G, "T") then
|
|
|
|
|
|
-- repeat test with extra closing upvalues
|
|
|
local function test ()
|
|
|
- local *toclose xxx = function (msg)
|
|
|
+ local *toclose xxx = func2close(function (self, msg)
|
|
|
assert(msg == "not enough memory");
|
|
|
error(1000) -- raise another error
|
|
|
- end
|
|
|
- local *toclose xx = function (msg)
|
|
|
+ end)
|
|
|
+ local *toclose xx = func2close(function (self, msg)
|
|
|
assert(msg == "not enough memory");
|
|
|
- end
|
|
|
+ end)
|
|
|
local *toclose x = enter(0) -- set a memory limit
|
|
|
-- creation of previous upvalue will raise a memory error
|
|
|
os.exit(false) -- should not run
|
|
@@ -413,9 +423,9 @@ do
|
|
|
local x = false
|
|
|
local y = false
|
|
|
local co = coroutine.create(function ()
|
|
|
- local *toclose xv = function () x = true end
|
|
|
+ local *toclose xv = func2close(function () x = true end)
|
|
|
do
|
|
|
- local *toclose yv = function () y = true end
|
|
|
+ local *toclose yv = func2close(function () y = true end)
|
|
|
coroutine.yield(100) -- yield doesn't close variable
|
|
|
end
|
|
|
coroutine.yield(200) -- yield doesn't close variable
|
|
@@ -453,9 +463,7 @@ do
|
|
|
end,
|
|
|
nil, -- state
|
|
|
nil, -- control variable
|
|
|
- function () -- closing function
|
|
|
- numopen = numopen - 1
|
|
|
- end
|
|
|
+ func2close(function () numopen = numopen - 1 end) -- closing function
|
|
|
end
|
|
|
|
|
|
local s = 0
|