diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-01-10 13:54:51 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-01-10 13:54:51 -0300 |
commit | 7ca3c40b50b385ead6b8bc4c54de97b61d11a12a (patch) | |
tree | 5c5998f39760b07e05135df56b8a828f2fb685c1 /testes/goto.lua | |
parent | 8a3a49250ce4a7e46ec9e90810a61d9f97aece3d (diff) | |
download | lua-7ca3c40b50b385ead6b8bc4c54de97b61d11a12a.tar.gz lua-7ca3c40b50b385ead6b8bc4c54de97b61d11a12a.tar.bz2 lua-7ca3c40b50b385ead6b8bc4c54de97b61d11a12a.zip |
Another way to compile goto's
The compilation of a goto or a label just create an entry and generate
boilerplate code for the gotos. As we don't know yet whether it needs a
CLOSE, we code a jump followed by a CLOSE, which is then dead code.
When a block ends (and then we know for sure whether there are variables
that need to be closed), we check the goto's against the labels of that
block. When closing a goto against a label, if it needs a CLOSE, the
compiler swaps the order of the jump and the CLOSE, making the CLOSE
active.
Diffstat (limited to 'testes/goto.lua')
-rw-r--r-- | testes/goto.lua | 35 |
1 files changed, 25 insertions, 10 deletions
diff --git a/testes/goto.lua b/testes/goto.lua index 4ac6d7d0..103cccef 100644 --- a/testes/goto.lua +++ b/testes/goto.lua | |||
@@ -250,21 +250,36 @@ assert(testG(3) == "3") | |||
250 | assert(testG(4) == 5) | 250 | assert(testG(4) == 5) |
251 | assert(testG(5) == 10) | 251 | assert(testG(5) == 10) |
252 | 252 | ||
253 | do | 253 | do -- test goto's around to-be-closed variable |
254 | -- if x back goto out of scope of upvalue | 254 | |
255 | local X | 255 | -- set 'var' and return an object that will reset 'var' when |
256 | -- it goes out of scope | ||
257 | local function newobj (var) | ||
258 | _ENV[var] = true | ||
259 | return setmetatable({}, {__close = function () | ||
260 | _ENV[var] = nil | ||
261 | end}) | ||
262 | end | ||
263 | |||
256 | goto L1 | 264 | goto L1 |
257 | 265 | ||
258 | ::L2:: goto L3 | 266 | ::L4:: assert(not X); goto L5 -- varX dead here |
259 | 267 | ||
260 | ::L1:: do | 268 | ::L1:: |
261 | local a <close> = setmetatable({}, {__close = function () X = true end}) | 269 | local varX <close> = newobj("X") |
262 | assert(X == nil) | 270 | assert(X); goto L2 -- varX alive here |
263 | if a then goto L2 end -- jumping back out of scope of 'a' | ||
264 | end | ||
265 | 271 | ||
266 | ::L3:: assert(X == true) -- checks that 'a' was correctly closed | 272 | ::L3:: |
273 | assert(X); goto L4 -- varX alive here | ||
274 | |||
275 | ::L2:: assert(X); goto L3 -- varX alive here | ||
276 | |||
277 | ::L5:: -- return | ||
267 | end | 278 | end |
279 | |||
280 | |||
281 | |||
282 | foo() | ||
268 | -------------------------------------------------------------------------------- | 283 | -------------------------------------------------------------------------------- |
269 | 284 | ||
270 | 285 | ||