github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/runtime/lua/locals.lua (about) 1 -- 2 -- const tests 3 -- 4 5 local function test(src) 6 local res, err = load(src) 7 if res ~= nil then 8 print(pcall(res)) 9 else 10 print(false, err) 11 end 12 end 13 14 test[[ 15 local foo <const> = 25 16 return foo 17 ]] 18 --> =true 25 19 20 test[[ 21 local foo <const> = "hello" 22 foo = "bye" 23 ]] 24 --> ~false\t.*attempt to reassign constant variable 'foo' 25 26 test[[ 27 local foo <const> = 25 28 local foo = foo + 2 29 return foo 30 ]] 31 --> =true 27 32 33 test[[ 34 local foo, bar <const> = 25, 32 35 do 36 local bar 37 bar = 72 38 end 39 foo = foo + 2 40 bar = bar - 1 41 return foo + bar 42 ]] 43 --> ~false\t.*attempt to reassign constant variable 'bar' 44 45 test[[ 46 local x <const> = 2 47 local function foo() 48 x = 3 49 return x 50 end 51 return foo() 52 ]] 53 --> ~false\t.*attempt to reassign constant variable 'x' 54 55 -- 56 -- to-be-closed tests 57 -- 58 59 test[[ 60 local x <close> = nil 61 x = 3 62 ]] 63 --> ~false\t.*attempt to reassign constant variable 'x' 64 65 test[[ 66 local x <close> = 1 67 ]] 68 --> ~false\t.*to be closed value missing a __close metamethod 69 70 function make(msg, err) 71 t = {} 72 setmetatable(t, {__close = function (x, e) 73 if e ~= nil then 74 print(msg, e) 75 else 76 print(msg) 77 end 78 if err ~= nil then 79 error(err) 80 end 81 end}) 82 return t 83 end 84 85 do 86 local x <close> = make("x") 87 print("a") 88 end 89 print("b") 90 --> =a 91 --> =x 92 --> =b 93 94 do 95 local x <close> = make("x") 96 local y <close> = make("y") 97 end 98 --> =y 99 --> =x 100 101 do 102 local x <close>, y <close> = make("aa"), make("bb") 103 end 104 --> =bb 105 --> =aa 106 107 -- errors in close metamethods. If a one produces an error, it looks like the 108 -- next one is fed that error. 109 pcall(function() 110 local x <close> = make("x") 111 local y <close> = make("y", "YY") 112 local z <close> = make("z") 113 local t <close> = make("t", "TT") 114 error("ERROR") 115 end) 116 --> ~t\t.*ERROR 117 --> ~z\t.*TT 118 --> ~y\t.*TT 119 --> ~x\t.*YY 120 121 -- A function to test to-be-closed variables 122 local s 123 function mk(a) 124 t = {} 125 s = s .. '+' .. a 126 setmetatable(t, {__close = function () s = s .. '-' .. a end}) 127 return t 128 end 129 130 -- How it works 131 do 132 s = "start" 133 local v <close> = mk("bob") 134 print(s) 135 --> =start+bob 136 end 137 print(s) 138 --> =start+bob-bob 139 140 do 141 s = "start" 142 local function f() 143 local a <close> = mk("a") 144 for i = 1, 3 do 145 local b <close> = mk("b"..i) 146 end 147 do 148 local c <close> = mk("c") 149 do 150 local d <close> = mk("d") 151 return 152 end 153 end 154 end 155 f() 156 print(s) 157 --> =start+a+b1-b1+b2-b2+b3-b3+c+d-d-c-a 158 end 159 160 do 161 s = "start" 162 local function f(n) 163 local x <close> = mk("x"..n) 164 if n > 0 then 165 f(n - 1) 166 else 167 error("stop") 168 end 169 end 170 print(pcall(f, 3)) 171 --> ~false\t.*: stop 172 print(s) 173 --> =start+x3+x2+x1+x0-x0-x1-x2-x3 174 end 175 176 do 177 print(pcall(function() 178 local x <close> = {} 179 print"we don't get to here" 180 end)) 181 --> ~false\t.*missing a __close metamethod 182 183 print(pcall(function() 184 local x <close> = mk("x") 185 getmetatable(x).__close = nil 186 local x <close> = make("haha") 187 print"we get here" 188 end)) 189 --> =we get here 190 --> =haha 191 --> ~false\t.*missing a __close metamethod 192 193 end 194 195 -- close actions are run before return debug hooks. The test below shows that 196 -- because 'myfunction' is output. 197 do 198 local function myfunction() 199 local function close() 200 debug.sethook(function() 201 print(debug.getinfo(2).name) 202 end, "r") 203 end 204 local t = {} 205 setmetatable(t, {__close=close}) 206 local x <close> = t 207 end 208 myfunction() 209 --> =sethook 210 --> =close 211 --> =myfunction 212 debug.sethook() 213 end 214 215 -- Tail calls are disabled when there are pending to-be-closed variables. 216 do 217 s = "start" 218 local function g() 219 local y <close> = mk("y") 220 end 221 local function f() 222 local x <close> = mk("x") 223 return g() -- This isn't a tail call 224 end 225 f() 226 print(s) 227 --> =start+x+y-y-x 228 -- x is closed after y, showing that g() wasn't a tail-call. 229 end