From 14c8fc3768d978205bf17ffc1905c2772afbd434 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 28 Aug 2024 16:47:38 -0400 Subject: Add `LL.setdtor()` function to add a "destructor" to any Lua object. `setdtor('description', object, function)` returns a proxy userdata object referencing object and function. When the proxy is garbage-collected, or at the end of the script, its destructor calls `function(object)`. The original object may be retrieved as `proxy._target`, e.g. to pass it to the `table` library. The proxy also has a metatable with metamethods supporting arithmetic operations, string concatenation, length and table indexing. For other operations, retrieve `proxy._target`. (But don't assign to `proxy._target`. It will appear to work, in that subsequent references to `proxy._target` will retrieve the replacement object -- however, the destructor will still call `function(original object)`.) Fix bugs in `lua_setfieldv()`, `lua_rawgetfield()` and `lua_rawsetfield()`. Add C++ functions `lua_destroyuserdata()` to explicitly destroy a `lua_emplace()` userdata object, plus `lua_destroybounduserdata()`. The latter can bind such a userdata object as an upvalue to pass to `LL.atexit()`. Make `LL.help()` and `LL.leaphelp()` help text include the `LL.` prefix. --- indra/newview/scripts/lua/test_setdtor.lua | 62 ++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 indra/newview/scripts/lua/test_setdtor.lua (limited to 'indra/newview/scripts/lua/test_setdtor.lua') diff --git a/indra/newview/scripts/lua/test_setdtor.lua b/indra/newview/scripts/lua/test_setdtor.lua new file mode 100644 index 0000000000..743c5168d0 --- /dev/null +++ b/indra/newview/scripts/lua/test_setdtor.lua @@ -0,0 +1,62 @@ +inspect = require 'inspect' + +print('initial setdtor') +bye = LL.setdtor('initial setdtor', 'Goodbye world!', print) + +print('arithmetic') +n = LL.setdtor('arithmetic', 11, print) +print("n =", n) +print("n._target =", n._target) +print("getmetatable(n) =", inspect(getmetatable(n))) +print("-n =", -n) +for i = 10, 12 do + -- Comparison metamethods are only called if both operands have the same + -- metamethod. + tempi = LL.setdtor('tempi', i, function(n) print('temp', i) end) + print(`n < {i}`, n < tempi) + print(`n <= {i}`, n <= tempi) + print(`n == {i}`, n == tempi) + print(`n ~= {i}`, n ~= tempi) + print(`n >= {i}`, n >= tempi) + print(`n > {i}`, n > tempi) +end +for i = 2, 3 do + print(`n + {i} =`, n + i) + print(`{i} + n =`, i + n) + print(`n - {i} =`, n - i) + print(`{i} - n =`, i - n) + print(`n * {i} =`, n * i) + print(`{i} * n =`, i * n) + print(`n / {i} =`, n / i) + print(`{i} / n =`, i / n) + print(`n % {i} =`, n % i) + print(`{i} % n =`, i % n) + print(`n ^ {i} =`, n ^ i) + print(`{i} ^ n =`, i ^ n) +end + +print('string') +s = LL.setdtor('string', 'hello', print) +print('s =', s) +print('#s =', #s) +print('s .. " world" =', s .. " world") +print('"world " .. s =', "world " .. s) + +print('table') +t = LL.setdtor('table', {'[1]', '[2]', abc='.abc', def='.def'}, + function(t) print(inspect(t)) end) +print('t =', inspect(t)) +print('t._target =', inspect(t._target)) +print('#t =', #t) +print('t[2] =', t[2]) +print('t.def =', t.def) +t[1] = 'new [1]' +print('t[1] =', t[1]) + +print('function') +f = LL.setdtor('function', function(a, b) return (a .. b) end, print) +print('f =', f) +print('f._target =', f._target) +print('f("Hello", " world") =', f("Hello", " world")) + +print('cleanup') -- cgit v1.2.3 From 364ea79ab3a4d48e0d10fbeabb9b8e88f226baac Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 28 Aug 2024 19:34:05 -0400 Subject: Prevent erroneous assignment to LL.setdtor() proxy._target field. Trim redundant output from test_setdtor.lua. --- indra/newview/scripts/lua/test_setdtor.lua | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'indra/newview/scripts/lua/test_setdtor.lua') diff --git a/indra/newview/scripts/lua/test_setdtor.lua b/indra/newview/scripts/lua/test_setdtor.lua index 743c5168d0..61ed86dcc8 100644 --- a/indra/newview/scripts/lua/test_setdtor.lua +++ b/indra/newview/scripts/lua/test_setdtor.lua @@ -7,6 +7,7 @@ print('arithmetic') n = LL.setdtor('arithmetic', 11, print) print("n =", n) print("n._target =", n._target) +print(pcall(function() n._target = 12 end)) print("getmetatable(n) =", inspect(getmetatable(n))) print("-n =", -n) for i = 10, 12 do @@ -20,20 +21,19 @@ for i = 10, 12 do print(`n >= {i}`, n >= tempi) print(`n > {i}`, n > tempi) end -for i = 2, 3 do - print(`n + {i} =`, n + i) - print(`{i} + n =`, i + n) - print(`n - {i} =`, n - i) - print(`{i} - n =`, i - n) - print(`n * {i} =`, n * i) - print(`{i} * n =`, i * n) - print(`n / {i} =`, n / i) - print(`{i} / n =`, i / n) - print(`n % {i} =`, n % i) - print(`{i} % n =`, i % n) - print(`n ^ {i} =`, n ^ i) - print(`{i} ^ n =`, i ^ n) -end +i = 2 +print(`n + {i} =`, n + i) +print(`{i} + n =`, i + n) +print(`n - {i} =`, n - i) +print(`{i} - n =`, i - n) +print(`n * {i} =`, n * i) +print(`{i} * n =`, i * n) +print(`n / {i} =`, n / i) +print(`{i} / n =`, i / n) +print(`n % {i} =`, n % i) +print(`{i} % n =`, i % n) +print(`n ^ {i} =`, n ^ i) +print(`{i} ^ n =`, i ^ n) print('string') s = LL.setdtor('string', 'hello', print) -- cgit v1.2.3 From 2d5cf36be6e0e367efec2bfa01378146269f33db Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 29 Aug 2024 21:36:39 -0400 Subject: Support next(), pairs(), ipairs() for LL.setdtor() table proxies. Replace the global next(), pairs() and ipairs() functions with a C++ function that drills down through layers of setdtor() proxy objects and then forwards the updated arguments to the original global function. Add a Luau __iter() metamethod to setdtor() proxy objects that, like other proxy metamethods, drills down to the underlying _target object. __iter() recognizes the case of a _target table which itself has a __iter() metamethod. Also add __idiv() metamethod to support integer division. Add tests for proxy // division, next(proxy), next(proxy, key), pairs(proxy), ipairs(proxy) and 'for k, v in proxy'. Also test the case where the table wrapped in the proxy has an __iter() metamethod of its own. --- indra/newview/scripts/lua/test_setdtor.lua | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'indra/newview/scripts/lua/test_setdtor.lua') diff --git a/indra/newview/scripts/lua/test_setdtor.lua b/indra/newview/scripts/lua/test_setdtor.lua index 61ed86dcc8..ec5cd47e93 100644 --- a/indra/newview/scripts/lua/test_setdtor.lua +++ b/indra/newview/scripts/lua/test_setdtor.lua @@ -30,6 +30,8 @@ print(`n * {i} =`, n * i) print(`{i} * n =`, i * n) print(`n / {i} =`, n / i) print(`{i} / n =`, i / n) +print(`n // {i} =`, n // i) +print(`{i} // n =`, i // n) print(`n % {i} =`, n % i) print(`{i} % n =`, i % n) print(`n ^ {i} =`, n ^ i) @@ -48,10 +50,37 @@ t = LL.setdtor('table', {'[1]', '[2]', abc='.abc', def='.def'}, print('t =', inspect(t)) print('t._target =', inspect(t._target)) print('#t =', #t) +print('next(t) =', next(t)) +print('next(t, 1) =', next(t, 1)) print('t[2] =', t[2]) print('t.def =', t.def) t[1] = 'new [1]' print('t[1] =', t[1]) +print('for k, v in pairs(t) do') +for k, v in pairs(t) do + print(`{k}: {v}`) +end +print('for k, v in ipairs(t) do') +for k, v in ipairs(t) do + print(`{k}: {v}`) +end +print('for k, v in t do') +for k, v in t do + print(`{k}: {v}`) +end +-- and now for something completely different +setmetatable( + t._target, + { + __iter = function(arg) + return next, {'alternate', '__iter'} + end + } +) +print('for k, v in t with __iter() metamethod do') +for k, v in t do + print(`{k}: {v}`) +end print('function') f = LL.setdtor('function', function(a, b) return (a .. b) end, print) -- cgit v1.2.3