diff options
-rw-r--r-- | ldo.c | 4 | ||||
-rw-r--r-- | lfunc.c | 32 | ||||
-rw-r--r-- | manual/manual.of | 7 | ||||
-rw-r--r-- | testes/locals.lua | 44 |
4 files changed, 60 insertions, 27 deletions
@@ -111,10 +111,6 @@ void luaD_seterrorobj (lua_State *L, TStatus errcode, StkId oldtop) { | |||
111 | setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); | 111 | setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); |
112 | break; | 112 | break; |
113 | } | 113 | } |
114 | case LUA_OK: { /* special case only for closing upvalues */ | ||
115 | setnilvalue(s2v(oldtop)); /* no error message */ | ||
116 | break; | ||
117 | } | ||
118 | default: { | 114 | default: { |
119 | lua_assert(errorstatus(errcode)); /* real error */ | 115 | lua_assert(errorstatus(errcode)); /* real error */ |
120 | setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */ | 116 | setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */ |
@@ -100,21 +100,23 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
100 | 100 | ||
101 | 101 | ||
102 | /* | 102 | /* |
103 | ** Call closing method for object 'obj' with error message 'err'. The | 103 | ** Call closing method for object 'obj' with error object 'err'. The |
104 | ** boolean 'yy' controls whether the call is yieldable. | 104 | ** boolean 'yy' controls whether the call is yieldable. |
105 | ** (This function assumes EXTRA_STACK.) | 105 | ** (This function assumes EXTRA_STACK.) |
106 | */ | 106 | */ |
107 | static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { | 107 | static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { |
108 | StkId top = L->top.p; | 108 | StkId top = L->top.p; |
109 | StkId func = top; | ||
109 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); | 110 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); |
110 | setobj2s(L, top, tm); /* will call metamethod... */ | 111 | setobj2s(L, top++, tm); /* will call metamethod... */ |
111 | setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ | 112 | setobj2s(L, top++, obj); /* with 'self' as the 1st argument */ |
112 | setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ | 113 | if (err != NULL) /* if there was an error... */ |
113 | L->top.p = top + 3; /* add function and arguments */ | 114 | setobj2s(L, top++, err); /* then error object will be 2nd argument */ |
115 | L->top.p = top; /* add function and arguments */ | ||
114 | if (yy) | 116 | if (yy) |
115 | luaD_call(L, top, 0); | 117 | luaD_call(L, func, 0); |
116 | else | 118 | else |
117 | luaD_callnoyield(L, top, 0); | 119 | luaD_callnoyield(L, func, 0); |
118 | } | 120 | } |
119 | 121 | ||
120 | 122 | ||
@@ -144,11 +146,17 @@ static void prepcallclosemth (lua_State *L, StkId level, TStatus status, | |||
144 | int yy) { | 146 | int yy) { |
145 | TValue *uv = s2v(level); /* value being closed */ | 147 | TValue *uv = s2v(level); /* value being closed */ |
146 | TValue *errobj; | 148 | TValue *errobj; |
147 | if (status == CLOSEKTOP) | 149 | switch (status) { |
148 | errobj = &G(L)->nilvalue; /* error object is nil */ | 150 | case LUA_OK: |
149 | else { /* 'luaD_seterrorobj' will set top to level + 2 */ | 151 | L->top.p = level + 1; /* call will be at this level */ |
150 | errobj = s2v(level + 1); /* error object goes after 'uv' */ | 152 | /* FALLTHROUGH */ |
151 | luaD_seterrorobj(L, status, level + 1); /* set error object */ | 153 | case CLOSEKTOP: /* don't need to change top */ |
154 | errobj = NULL; /* no error object */ | ||
155 | break; | ||
156 | default: /* 'luaD_seterrorobj' will set top to level + 2 */ | ||
157 | errobj = s2v(level + 1); /* error object goes after 'uv' */ | ||
158 | luaD_seterrorobj(L, status, level + 1); /* set error object */ | ||
159 | break; | ||
152 | } | 160 | } |
153 | callclosemethod(L, uv, errobj, yy); | 161 | callclosemethod(L, uv, errobj, yy); |
154 | } | 162 | } |
diff --git a/manual/manual.of b/manual/manual.of index a55c7b49..ff4e79fe 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
@@ -1612,10 +1612,11 @@ or exiting by an error. | |||
1612 | Here, to @emph{close} a value means | 1612 | Here, to @emph{close} a value means |
1613 | to call its @idx{__close} metamethod. | 1613 | to call its @idx{__close} metamethod. |
1614 | When calling the metamethod, | 1614 | When calling the metamethod, |
1615 | the value itself is passed as the first argument | 1615 | the value itself is passed as the first argument. |
1616 | and the error object that caused the exit (if any) | 1616 | If there was an error, |
1617 | the error object that caused the exit | ||
1617 | is passed as a second argument; | 1618 | is passed as a second argument; |
1618 | if there was no error, the second argument is @nil. | 1619 | otherwise, there is no second argument. |
1619 | 1620 | ||
1620 | The value assigned to a to-be-closed variable | 1621 | The value assigned to a to-be-closed variable |
1621 | must have a @idx{__close} metamethod | 1622 | must have a @idx{__close} metamethod |
diff --git a/testes/locals.lua b/testes/locals.lua index 090d846b..910deb8a 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
@@ -280,6 +280,32 @@ do | |||
280 | end | 280 | end |
281 | 281 | ||
282 | 282 | ||
283 | do -- testing presence of second argument | ||
284 | local function foo (howtoclose, obj, n) | ||
285 | local ca -- copy of 'a' visible inside its close metamethod | ||
286 | do | ||
287 | local a <close> = func2close(function (...) | ||
288 | local t = table.pack(...) | ||
289 | assert(select("#", ...) == n) | ||
290 | assert(t.n == n and t[1] == ca and (t.n < 2 or t[2] == obj)) | ||
291 | ca = 15 -- final value to be returned if howtoclose=="scope" | ||
292 | end) | ||
293 | ca = a | ||
294 | if howtoclose == "ret" then return obj -- 'a' closed by return | ||
295 | elseif howtoclose == "err" then error(obj) -- 'a' closed by error | ||
296 | end | ||
297 | end -- 'a' closed by end of scope | ||
298 | return ca -- ca now should be 15 | ||
299 | end | ||
300 | -- with no errors, closing methods receive no extra argument | ||
301 | assert(foo("scope", nil, 1) == 15) -- close by end of scope | ||
302 | assert(foo("ret", 32, 1) == 32) -- close by return | ||
303 | -- with errors, they do | ||
304 | local st, msg = pcall(foo, "err", 23, 2) -- close by error | ||
305 | assert(not st and msg == 23) | ||
306 | end | ||
307 | |||
308 | |||
283 | -- testing to-be-closed x compile-time constants | 309 | -- testing to-be-closed x compile-time constants |
284 | -- (there were some bugs here in Lua 5.4-rc3, due to a confusion | 310 | -- (there were some bugs here in Lua 5.4-rc3, due to a confusion |
285 | -- between compile levels and stack levels of variables) | 311 | -- between compile levels and stack levels of variables) |
@@ -865,8 +891,10 @@ do | |||
865 | if extra then | 891 | if extra then |
866 | extrares = co() -- runs until first (extra) yield | 892 | extrares = co() -- runs until first (extra) yield |
867 | end | 893 | end |
868 | local res = table.pack(co()) -- runs until yield inside '__close' | 894 | local res = table.pack(co()) -- runs until "regular" yield |
869 | assert(res.n == 2 and res[2] == nil) | 895 | -- regular yield will yield all values passed to the close function; |
896 | -- without errors, that is only the object being closed. | ||
897 | assert(res.n == 1 and type(res[1]) == "table") | ||
870 | local res2 = table.pack(co()) -- runs until end of function | 898 | local res2 = table.pack(co()) -- runs until end of function |
871 | assert(res2.n == t.n) | 899 | assert(res2.n == t.n) |
872 | for i = 1, #t do | 900 | for i = 1, #t do |
@@ -879,10 +907,10 @@ do | |||
879 | end | 907 | end |
880 | 908 | ||
881 | local function foo () | 909 | local function foo () |
882 | local x <close> = func2close(coroutine.yield) | 910 | local x <close> = func2close(coroutine.yield) -- "regular" yield |
883 | local extra <close> = func2close(function (self) | 911 | local extra <close> = func2close(function (self) |
884 | assert(self == extrares) | 912 | assert(self == extrares) |
885 | coroutine.yield(100) | 913 | coroutine.yield(100) -- first (extra) yield |
886 | end) | 914 | end) |
887 | extrares = extra | 915 | extrares = extra |
888 | return table.unpack{10, x, 30} | 916 | return table.unpack{10, x, 30} |
@@ -891,21 +919,21 @@ do | |||
891 | assert(extrares == 100) | 919 | assert(extrares == 100) |
892 | 920 | ||
893 | local function foo () | 921 | local function foo () |
894 | local x <close> = func2close(coroutine.yield) | 922 | local x <close> = func2close(coroutine.yield) -- "regular" yield |
895 | return | 923 | return |
896 | end | 924 | end |
897 | check(foo, false) | 925 | check(foo, false) |
898 | 926 | ||
899 | local function foo () | 927 | local function foo () |
900 | local x <close> = func2close(coroutine.yield) | 928 | local x <close> = func2close(coroutine.yield) -- "regular" yield |
901 | local y, z = 20, 30 | 929 | local y, z = 20, 30 |
902 | return x | 930 | return x |
903 | end | 931 | end |
904 | check(foo, false, "x") | 932 | check(foo, false, "x") |
905 | 933 | ||
906 | local function foo () | 934 | local function foo () |
907 | local x <close> = func2close(coroutine.yield) | 935 | local x <close> = func2close(coroutine.yield) -- "regular" yield |
908 | local extra <close> = func2close(coroutine.yield) | 936 | local extra <close> = func2close(coroutine.yield) -- extra yield |
909 | return table.unpack({}, 1, 100) -- 100 nils | 937 | return table.unpack({}, 1, 100) -- 100 nils |
910 | end | 938 | end |
911 | check(foo, true, table.unpack({}, 1, 100)) | 939 | check(foo, true, table.unpack({}, 1, 100)) |