According to the documentation _G "holds the global environment". I wanted to see what's inside it so I wrote the following code to print _G but it doesn't work:
function f(x)
return 2*x
end
a=3
b="hello world"
print("_G has "..#_G.." elements")
for k,v in pairs(_G) do
print(k)
print(_G[k])
print("G["..k.."]=".._G[k])
end
Error:
_G has 0 elements
a
3
G[a]=3
string
table: 003C8448
lua: try_G.lua:10: attempt to concatenate field '?' (a table value)
stack traceback:
try_G.lua:10: in main chunk
[C]: ?
>Exit code: 1
You could also use the table.foreach(t,f) function. It iterates over a table t, calling the function f with each key and value pair. Use with print to get a quick view:
table.foreach(_G,print)
This is really handy at the interactive prompt as it is reasonably succinct and easy enough to type.
C:\Users\Ross>lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> table.foreach(_G,print)
string table: 005CE3D0
xpcall function: 00717E80
package table: 005CE088
tostring function: 00717DE0
print function: 00711CB8
os table: 005CE358
unpack function: 00717E40
require function: 00718360
getfenv function: 00711B58
setmetatable function: 00717DA0
next function: 00711C38
assert function: 00711A38
tonumber function: 00717DC0
io table: 005CE218
rawequal function: 00711CF8
collectgarbage function: 00711A78
getmetatable function: 00711B98
module function: 00718320
rawset function: 00711D58
math table: 005CE448
debug table: 005CE498
pcall function: 00711C78
table table: 005CE128
newproxy function: 00711E10
type function: 00717E00
coroutine table: 005CDFE8
_G table: 00713EC8
select function: 00711D98
gcinfo function: 00711B18
pairs function: 00711F98
rawget function: 00711D18
loadstring function: 00711C18
ipairs function: 00711F68
_VERSION Lua 5.1
dofile function: 00711A98
setfenv function: 00717D60
load function: 00711BD8
error function: 00711AD8
loadfile function: 00711BB8
>
Update: Unfortunately, as Alexander Gladysh reminds me, the table.foreach function was deprecated in Lua 5.1, and a quick check of the current beta release of 5.2 shows that it has been removed in Lua 5.2. It is easy to write the same loop in terms of pairs:
for k,v in pairs(_G) do print(k,v) end
which should give the same output as table.foreach(_G,print) would. The key feature that I'm leaning on here is that print is defined to call tostring() on each argument you pass, and tostring() is defined to return some sort of sensible string for every kind of value, even those like functions that don't have a good representation as a string. The details will differ on each platform, but the default implementation of tostring() includes the address of the table or function in its string result, allowing you to at least recognize that _G.os and _G.io are distinct tables.
For more human-friendly table printing, there are a lot of solutions, ranging from examples in PiL to several persistent data libraries. Personally, I like the pl.pretty.write() function provided by steve donavan's penlight library.
Your code works exactly as expected- it loops through _G and attempts to print the contents. Unfortunately, _G contains many tables which cannot be concatenated into a string. The code fails because _G["_G"] = _G. That means that when the interpreter comes to
print("G["..k.."]=".._G[k])
then k is "_G" and _G[k] is _G, and you attempt to concatenate a table- which the interpreter can't do, so it dies on you. There are numerous other tables in _G which would also cause this failure.
To follow up on DeadMG, change your
print("G["..k.."]=".._G[k])
to
print("G["..k.."]=",_G[k])
and you should be fine.
Here is the final code using DeadMG's solution:
function f(x)
return 2*x
end
a=3
b="hello world"
print("_G has "..#_G.." elements")
for k,v in pairs(_G) do
if k~="_G" then
if type(v)=="string" or type(v)=="number" then
print("G["..k.."]="..v)
else
print("G["..k.."]=("..type(v)..")")
end
end
end
Related
Lua will write the code of a function out as bytes using string.dump, but warns that this does not work if there are any upvalues. Various snippets online describe hacking around this with debug. It looks like 'closed over variables' are called 'upvalues', which seems clear enough. Code is not data etc.
I'd like to serialise functions and don't need them to have any upvalues. The serialised function can take a table as an argument that gets serialised separately.
How do I detect attempts to pass closures to string.dump, before calling the broken result later?
Current thought is debug.getupvalue at index 1 and treat nil as meaning function, as opposed to closure, but I'd rather not call into the debug interface if there's an alternative.
Thanks!
Even with debug library it's very difficult to say whether a function has a non-trivial upvalue.
"Non-trivial" means "upvalue except _ENV".
When debug info is stripped from your program, all upvalues look almost the same :-)
local function test()
local function f1()
-- usual function without upvalues (except _ENV for accessing globals)
print("Hello")
end
local upv = {}
local function f2()
-- this function does have an upvalue
upv[#upv+1] = ""
end
-- display first upvalues
print(debug.getupvalue (f1, 1))
print(debug.getupvalue (f2, 1))
end
test()
local test_stripped = load(string.dump(test, true))
test_stripped()
Output:
_ENV table: 00000242bf521a80 -- test f1
upv table: 00000242bf529490 -- test f2
(no name) table: 00000242bf521a80 -- test_stripped f1
(no name) table: 00000242bf528e90 -- test_stripped f2
The first two lines of the output are printed by test(), the last two lines by test_stripped().
As you see, inside test_stripped functions f1 and f2 are almost undistinguishable.
Is it possibly to dump the Lua table including function arguments?
If so, how can I do it?
I have managed to dump tables and function with addresses, but I haven't been able to figure out a way to get function args, i have tried different methods, but no luck.
So I want to receive them truth dumping tables and function plus args of the function.
Output should be something like this: Function JumpHigh(Player, height)
I don't know if it is even possible, but would be very handy.
Table only stores values.
If there's function stored in a table, then it's just a function body, there's no arguments. If arguments were applied, table would store only final result of that call.
Maybe you're talking about closure - function returned from other function, capturing some arguments from a top level function in a lexical closure? Then see debug.getupvalue() function to check closure's content.
Is this something what you're asking?
local function do_some_action(x,y)
return function()
print(x,y)
end
end
local t = {
func = do_some_action(123,478)
}
-- only function value printed
print "Table content:"
for k,v in pairs(t) do
print(k,v)
end
-- list function's upvalues, where captured arguments may be stored
print "Function's upvalues"
local i = 0
repeat
i = i + 1
local name, val = debug.getupvalue(t.func, i)
if name then
print(name, val)
end
until not name
Note that upvalues stored is not necessary an argument to a toplevel function. It might be some local variable, storing precomputed value for the inner function.
Also note that if script was precompiled into Lua bytecode with stripping debug info, then you won't get upvalues' names, those will be empty.
Is it possible to print a table without using metatables in Lua?
In Roberto's book Programming in Lua, he mentions "The function print always calls tostring to format its output". However, if I override tostring in my table, then I get the following results:
> a = {}
> a.tostring = function() return "Lua is cool" end
> print(a)
table: 0x24038c0
It can NOT be done without metatables.
The function print always calls tostring to format its output.
You misunderstood this. Here, tostring is the function tostring, not a field of a table. So what it means is that print(t) will call print(tosstring(t)), that's it.
For tables, tostring(t) will then find if it has a metamethod __tostring, and uses that as the result. So eventually, you still need a metatable.
local t = {}
local mt = {__tostring = function() return "Hello Lua" end}
setmetatable(t, mt)
print(t)
I want to know how to get the table hex id. I know that doing:
local some_var = {}
print (some_var)
the result is (for instance):
table: 0x21581c0
I want the hex without the table: string. I know that maybe some of you suggest me to make a regular expression (or something similar) to remove those chars, but I want to avoid that, and just get the 0x21581c0
Thanks
This is simpler and works for all types that are associated with pointers:
local function getId(t)
return string.format("%p", t)
end
print("string:", getId("hi"))
print("table:", getId({}))
print("userdata:", getId(io.stdin))
print("function:", getId(print))
print("number:", getId(1))
print("boolean:", getId(false))
print("nil:", getId(nil))
Result:
string: 0x0109f04638
table: 0x0109f0a270
userdata: 0x01098076c8
function: 0x0109806018
number: NULL
boolean: NULL
nil: NULL
In the standard implementation, there is the global 'print' variable that refers to a standard function that calls, through the global variable 'tostring', a standard function described here. The stanard 'tostring' function is the only way to retrieve the hexadecimal number it shows for a table.
Unfortunately, there is no configuration for either of the functions to do anything differently for all tables.
Nonetheless, there are several points for modification. You can create you own function and call that every time instead, or point either of the the global variables print or tostring to you own functions. Or, set a __tostring metamethod on each table you need tostring to return a different answer for. The advantage to this is it gets you the format you want with only one setup step. The disadvantage is that you have to set up each table.
local function simplifyTableToString(t)
local answer = tostring(t):gsub("table: ", "", 1)
local mt = getmetatable(t)
if not mt then
mt = {}
setmetatable(t, mt)
end
mt.__tostring = function() return answer end
end
local a = {}
local b = {}
print(a, b)
simplifyTableToString(a)
print(a, b)
Without complex patterns, you can just search for the first space, and grab the substring of what follows.
function get_mem_addr (object)
local str = tostring(object)
return str:sub(str:find(' ') + 1)
end
print(get_mem_addr({})) -- 0x109638
print(get_mem_addr(function () end)) -- 0x108cf8
This function will work with tables and functions, but expect errors if you pass it anything else.
Or you can use a little type checking:
function get_mem_addr (o)
return tostring(o):sub(type(o):len() + 3)
end
The table id stated by the OP is invalid in the version of Lua I am using (5.1 in Roblox). A valid ID is length 8, not 9 as in your example. Either way, just use string.sub to get the sub-string you are after.
string.sub(tostring({}), 8)
The reason is, 'table: ' is 7 characters long, so we take from index 8 through the end of the string which returns the hex value.
In Lua, you can convert a function to a string where it returns what appears to be an address
print(print)
function: 0x41a360
Is it possible to do the reverse? e.g.
local aliasPrint = function: 0x41a360
aliasPrint("Hello, World!")
Hello, World!
I looked around online for a solution, but my google-fu may be lacking.
Actually, you are not converting a function to a string. string.dump does that in limited cases. And, load is the inverse.
local function f()
print("I'm a function")
end
local d = string.dump(f)
print(string.format("%q", d))
local g = load(d);
g()
As to your approach, I can only ask, "Why?"
tostring is a function that gives a notional representation of an object with essential information. In many cases, (functions and tables), uniqueness is an essential property. So, tostring includes that in its representation. Many languages have something similar but don't always show uniqueness. (Some do show more properties in a debugger.)
Lua does not have reflection, but the function names are stored as string in memory as a "key". You can achieve in a similar way
local aliasPrint = _ENV["print"]
aliasPrint("Hello, World!")
output:
Hello, World!
_ENV is the lookup table of the running environment of Lua global variables (for Lua v5.1-, use _env instead)
If you are using a function in an object, just substitude _ENV["print"] by table_or_object["function_name"].