From d881325c2fcbb6d2c434ec403b0bbe51ac200c7b Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Thu, 9 May 2019 12:10:31 -0300 Subject: [PATCH] Flag for to-be-closed variables changed to '' The flag for to-be-closed variables was changed from '*toclose' to ''. Several people found confusing the old syntax and the new one has a clear terminator, making it more flexible for future changes. --- lparser.c | 3 ++- manual/manual.of | 4 ++-- testes/api.lua | 3 ++- testes/coroutine.lua | 6 +++--- testes/files.lua | 6 +++--- testes/goto.lua | 2 +- testes/locals.lua | 50 ++++++++++++++++++++++---------------------- testes/main.lua | 4 ++-- 8 files changed, 40 insertions(+), 38 deletions(-) diff --git a/lparser.c b/lparser.c index 4c2ddbfe..4e6c27fe 100644 --- a/lparser.c +++ b/lparser.c @@ -1621,6 +1621,7 @@ static void tocloselocalstat (LexState *ls) { if (strcmp(getstr(attr), "toclose") != 0) luaK_semerror(ls, luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr))); + testnext(ls, '>'); new_localvar(ls, str_checkname(ls)); checknext(ls, '='); exp1(ls); @@ -1634,7 +1635,7 @@ static void tocloselocalstat (LexState *ls) { static void localstat (LexState *ls) { /* stat -> LOCAL NAME {',' NAME} ['=' explist] | LOCAL *toclose NAME '=' exp */ - if (testnext(ls, '*')) + if (testnext(ls, '<')) tocloselocalstat(ls); else commonlocalstat(ls); diff --git a/manual/manual.of b/manual/manual.of index cf44b4f2..54a07879 100644 --- a/manual/manual.of +++ b/manual/manual.of @@ -1509,7 +1509,7 @@ A local variable can be declared as a @def{to-be-closed} variable, with the following syntax: @Produc{ @producname{stat}@producbody{ - @Rw{local} @bnfter{*} @bnfter{toclose} Name @bnfter{=} exp + @Rw{local} @bnfter{<} @bnfter{toclose} @bnfter{>} Name @bnfter{=} exp }} A to-be-closed variable behaves like a normal local variable, except that its value is @emph{closed} whenever the variable @@ -8949,7 +8949,7 @@ and @bnfNter{LiteralString}, see @See{lexical}.) @OrNL @Rw{function} funcname funcbody @OrNL @Rw{local} @Rw{function} @bnfNter{Name} funcbody @OrNL @Rw{local} namelist @bnfopt{@bnfter{=} explist} -@OrNL @Rw{local} @bnfter{*} @bnfter{toclose} Name @bnfter{=} exp +@OrNL @Rw{local} @bnfter{<} @bnfter{toclose} @bnfter{>} Name @bnfter{=} exp } @producname{retstat}@producbody{@Rw{return} diff --git a/testes/api.lua b/testes/api.lua index 08672e8a..bcc04dac 100644 --- a/testes/api.lua +++ b/testes/api.lua @@ -1137,7 +1137,8 @@ end) testamem("to-be-closed variables", function() local flag do - local *toclose x = setmetatable({}, {__close = function () flag = true end}) + local x = + setmetatable({}, {__close = function () flag = true end}) flag = false local x = {} end diff --git a/testes/coroutine.lua b/testes/coroutine.lua index 9dd501e7..db6d074e 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua @@ -151,7 +151,7 @@ do end co = coroutine.create(function () - local *toclose x = func2close(function (self, err) + local x = func2close(function (self, err) assert(err == nil); X = false end) X = true @@ -164,7 +164,7 @@ do -- error killing a coroutine co = coroutine.create(function() - local *toclose x = func2close(function (self, err) + local x = func2close(function (self, err) assert(err == nil); error(111) end) coroutine.yield() @@ -348,7 +348,7 @@ do local X = false A = coroutine.wrap(function() - local *toclose _ = setmetatable({}, {__close = function () X = true end}) + local _ = setmetatable({}, {__close = function () X = true end}) return pcall(A, 1) end) st, res = A() diff --git a/testes/files.lua b/testes/files.lua index 38d3a669..eb100fe1 100644 --- a/testes/files.lua +++ b/testes/files.lua @@ -125,7 +125,7 @@ do -- closing file by scope local F = nil do - local *toclose f = assert(io.open(file, "w")) + local f = assert(io.open(file, "w")) F = f end assert(tostring(F) == "file (closed)") @@ -135,7 +135,7 @@ assert(os.remove(file)) do -- test writing/reading numbers - local *toclose f = assert(io.open(file, "w")) + local f = assert(io.open(file, "w")) f:write(maxint, '\n') f:write(string.format("0X%x\n", maxint)) f:write("0xABCp-3", '\n') @@ -158,7 +158,7 @@ assert(os.remove(file)) -- testing multiple arguments to io.read do - local *toclose f = assert(io.open(file, "w")) + local f = assert(io.open(file, "w")) f:write[[ a line another line diff --git a/testes/goto.lua b/testes/goto.lua index f3dcfd4a..c9e48073 100644 --- a/testes/goto.lua +++ b/testes/goto.lua @@ -258,7 +258,7 @@ do ::L2:: goto L3 ::L1:: do - local *toclose a = setmetatable({}, {__close = function () X = true end}) + local a = setmetatable({}, {__close = function () X = true end}) assert(X == nil) if a then goto L2 end -- jumping back out of scope of 'a' end diff --git a/testes/locals.lua b/testes/locals.lua index 814d1b16..c176f506 100644 --- a/testes/locals.lua +++ b/testes/locals.lua @@ -185,9 +185,9 @@ end do local a = {} do - local *toclose x = setmetatable({"x"}, {__close = function (self) + local x = setmetatable({"x"}, {__close = function (self) a[#a + 1] = self[1] end}) - local *toclose y = func2close(function (self, err) + local y = func2close(function (self, err) assert(err == nil); a[#a + 1] = "y" end) a[#a + 1] = "in" @@ -203,7 +203,7 @@ do -- closing functions do not corrupt returning values local function foo (x) - local *toclose _ = closescope + local _ = closescope return x, X, 23 end @@ -212,7 +212,7 @@ do X = false foo = function (x) - local *toclose _ = closescope + local _ = closescope local y = 15 return y end @@ -221,7 +221,7 @@ do X = false foo = function () - local *toclose x = closescope + local x = closescope return x end @@ -234,13 +234,13 @@ do -- calls cannot be tail in the scope of to-be-closed variables local X, Y local function foo () - local *toclose _ = func2close(function () Y = 10 end) + local _ = 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 _ = func2close(function () X = false end) + local _ = func2close(function () X = false end) X = true do return foo() -- not a tail call! @@ -255,14 +255,14 @@ end do -- errors in __close local log = {} local function foo (err) - local *toclose x = + local x = func2close(function (self, msg) log[#log + 1] = msg; error(1) end) - local *toclose x1 = + local x1 = func2close(function (self, msg) log[#log + 1] = msg; end) - local *toclose gc = func2close(function () collectgarbage() end) - local *toclose y = + local gc = func2close(function () collectgarbage() end) + local y = func2close(function (self, msg) log[#log + 1] = msg; error(2) end) - local *toclose z = + local z = func2close(function (self, msg) log[#log + 1] = msg or 10; error(3) end) if err then error(4) end end @@ -283,7 +283,7 @@ do -- errors due to non-closable values local function foo () - local *toclose x = 34 + local x = 34 end local stat, msg = pcall(foo) assert(not stat and string.find(msg, "variable 'x'")) @@ -291,8 +291,8 @@ do -- with other errors, non-closable values are ignored local function foo () - local *toclose x = 34 - local *toclose y = func2close(function () error(32) end) + local x = 34 + local y = func2close(function () error(32) end) end local stat, msg = pcall(foo) assert(not stat and msg == 32) @@ -304,8 +304,8 @@ if rawget(_G, "T") then -- memory error inside closing function local function foo () - local *toclose y = func2close(function () T.alloccount() end) - local *toclose x = setmetatable({}, {__close = function () + local y = func2close(function () T.alloccount() end) + local x = setmetatable({}, {__close = function () T.alloccount(0); local x = {} -- force a memory error end}) error("a") -- common error inside the function's body @@ -331,7 +331,7 @@ if rawget(_G, "T") then end local function test () - local *toclose x = enter(0) -- set a memory limit + local x = enter(0) -- set a memory limit -- creation of previous upvalue will raise a memory error assert(false) -- should not run end @@ -346,14 +346,14 @@ if rawget(_G, "T") then -- repeat test with extra closing upvalues local function test () - local *toclose xxx = func2close(function (self, msg) + local xxx = func2close(function (self, msg) assert(msg == "not enough memory"); error(1000) -- raise another error end) - local *toclose xx = func2close(function (self, msg) + local xx = func2close(function (self, msg) assert(msg == "not enough memory"); end) - local *toclose x = enter(0) -- set a memory limit + local x = enter(0) -- set a memory limit -- creation of previous upvalue will raise a memory error os.exit(false) -- should not run end @@ -424,9 +424,9 @@ do local x = false local y = false local co = coroutine.wrap(function () - local *toclose xv = func2close(function () x = true end) + local xv = func2close(function () x = true end) do - local *toclose yv = func2close(function () y = true end) + local yv = func2close(function () y = true end) coroutine.yield(100) -- yield doesn't close variable end coroutine.yield(200) -- yield doesn't close variable @@ -446,7 +446,7 @@ do -- error in a wrapped coroutine raising errors when closing a variable local x = false local co = coroutine.wrap(function () - local *toclose xv = func2close(function () error("XXX") end) + local xv = func2close(function () error("XXX") end) coroutine.yield(100) error(200) end) @@ -461,7 +461,7 @@ end -- a suspended coroutine should not close its variables when collected local co co = coroutine.wrap(function() - local *toclose x = function () os.exit(false) end -- should not run + local x = function () os.exit(false) end -- should not run co = nil coroutine.yield() end) diff --git a/testes/main.lua b/testes/main.lua index aab490c8..47d84d4c 100644 --- a/testes/main.lua +++ b/testes/main.lua @@ -320,11 +320,11 @@ NoRun("", "lua %s", prog) -- no message -- to-be-closed variables in main chunk prepfile[[ - local *toclose x = function (err) + local x = function (err) assert(err == 120) print("Ok") end - local *toclose e1 = function () error(120) end + local e1 = function () error(120) end os.exit(true, true) ]] RUN('lua %s > %s', prog, out)