nil value after loadstring on a table - lua

I'm doing a loadstring() on a table but the result is still a nil value for my variable m.
I guess I would expect it to be a table. What am I missing with loadstring()? Does it not work this way?
local m = assert (loadstring("data = { [1] = 10}"))()

Your code inside loadstring should probably be "return {10}".
After running that code, m will be nil, but you'll have a global data.

Related

Love2d adding value to table inside for loop.. Using a variable

This is something that's really been nagging at me for some time:
for i = 1, 4 do
x = love.physics.newFixture(diffTable[i].body, diffTable[i].shape):setCategory(10)
x = x:setUserData('Border') -- error here
table.insert(data, x)
end
Let's say I want to insert a variable into the table (basically creating the variable, and then modifying it) and then inserting it:
When I do the x = x:setUserData(...) an error comes up.. saying attempt to index global variable x (nil)
So my question is, how would I create a variable inside a for loop, specifically
I need to do it this way because I'm using love.physics, and creating a fixture with a category. I also need to setUserData at that time but it's not possible.
And I'm sure there has to be a way of doing this...
Thanks in advance!!
The function Fixture:setCategory does not return a value.
so when you do this
x = love.physics.newFixture(diffTable[i].body, diffTable[i].shape):setCategory(10)
you are setting x = nil.
Fixture:setUserData also does not return a value.
If you change it to this you will no longer get that error.
for i = 1, 4 do
x = love.physics.newFixture(diffTable[i].body, diffTable[i].shape)
x:setCategory(10)
x:setUserData('Border') -- error here
table.insert(data, x)
end

Lua - get table hex identifier

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.

lua - how to initialize a table using a string

I have the following string:
mystring = "a=test;b=12345"
I would like to know how to initialize a table in one shot, assign it the value of the string. The string originates from another external application, and if possible I want to avoid having to split it up. Something like this:
mytable = {mystring:gsub(";",",")}
Is it possible to do something like this? I know how to do it in multiple steps... but just wondering if it's possible to do it all at once.
Here's what I've tried and the respective output:
> mystring = "a=123;b=2345"
> myarray = {mystring:gsub(";",",")}
> for key,value in pairs(myarray) do print(key,value) end
1 a=123,b=2345
2 1
>
whereas I was hoping to end up with an array / table where like this:
key value
a 123
b 2345
-- Lua 5.2+ required
function string_to_table (str)
local result = {}
load(str, '', 't', setmetatable({}, {
__index = function(t,k) return k end,
__newindex = result
}))()
return result
end
mytable = string_to_table("a=test;b=12345;c=a") -- {a="test", b=12345, c="a"}
Try this, which lets Lua do the hard work:
function parse(s)
local t={}
load(s,"",nil,t)()
return t
end
mytable=parse("a=123;b=2345")
for k,v in pairs(mytable) do print(k,v) end
Note that this executes the code in the given string, which may be dangerous if it comes from an untrusted source. On the other hand, the damage is limited because the code is executed in an empty environment and so cannot affect existing variables. Malicious code may contain infinite loops or consume all memory, though.
mytable = {}
for key, value in string.gmatch("a=123;b=456", "(%w+)=(%w+)") do
mytable[key] = value
end
print(mytable.a, mytable.b)
Returns:
123
456
as expected. This only works, of course, with alphanumeric and no punctuation.

Lua: attempt to perform arithmetic on global 'mapfinishes' (a nil value)

I'm trying to set up something in a game that runs off of Lua and this specific local function is triggered when the player finishes the map. Here is the code:
local function setDrRanks( ply )
local name = SQLStr( ply:Nick() )
local sid = ply:SteamID()
drsql:query( "SELECT MapFinishes from dr_exp WHERE SteamID = '"..sid.."'", function( q, data )
local row = data[1]
if ( row ) then
mapfinishes = row["Mapfinishes"]
end
drsql:query( "REPLACE into dr_exp (`SteamID`, `PlayerName`, `MapFinishes`) VALUES('"..sid.."', "..name..", '"..(mapfinishes+1).."');" );
end )
end
The function is to insert into SQL via a lua function, which it did successfully when ran the first time, as the player was at 0 finishes. Once they hit 1, it refused to do a simple +1 on the mapfinishes value. Which strange is that this seems to work 100% when the player is at 0 finishes, and it will put them at 1, but once they are at 1, it will not add to it any longer. The error received is:
attempt to perform arithmetic on global 'mapfinishes' (a nil value)
Anyone have any ideas? Thanks in advance.
local row = data[1]
if ( row ) then
mapfinishes = row["Mapfinishes"]
end
drsql:query( "REPLACE into dr_exp (`SteamID`, `PlayerName`, `MapFinishes`) VALUES('"..sid.."', "..name..", '"..(mapfinishes+1).."');" )
The issue is in the expression mapfinishes+1 which seems to have gotten executed without mapfinishes getting set. This implies that the if loop above didn't execute because row was nil or false. Remember, in Lua, zero and the empty string are truth values.
Another possibility is that the row["Mapfinishes"] itself was nil so that mapfinishes remains nil.
Usually it's better to have minimal/no global variables. If you're going to use mapfinishes only within this function, it'd be appropriate to declare it local.

Meta metatables?

I'm trying to make an __index function in my table which can process ALL of the field it receives.. What I want to do is that if I call the table in the following way
mytable.str1.str2.str3
I should be able to return the table
{"str1", "str2", "str3"}
Note that str1,str2,str3 are undefined, they are just strings. I am not trying to create subtables str1, str2, I just want __index to see everything beyond the first period.
Unfortunately what I have seems that __index only captures str1, and complains that "attempt to index field 'str1' (a nil value)"
Anyone know how this can be done?
I'm not sure why you'd want to do this, but here's how you do it. The comments explain the trick, but basically you need a second metatable to handle the table that's returned from the first call to the __index metamethod.
If this isn't clear, let me know and I can explain in more detail.
-- This metatable appends the new key to itself, then returns itself
stringtablemeta = {}
function stringtablemeta.__index(self, key)
table.insert(self, key)
return self
end
-- In response to the question in the comments:
function stringtablemeta.__tostring(self)
local str = ""
for i, v in ipairs(self) do
if i > 1 then str = str .. "-" end
str = str .. v
end
return str
end
-- This metatable creates a new table, with stringmetatable as its metatable
mytablemeta = {}
function mytablemeta.__index(self, key)
local temp = { key }
setmetatable(temp, stringtablemeta)
return temp
end
-- set mytable to have mymetatable as it's metatable. This makes it so when
-- you index into it, it will call the mytablemeta.__index method.
--
-- That will return a talb with a single string, the key that was passed
-- in. that table will have it's own metatable, the stringmetatable, which
-- will cause it to append keys that are called on it with its own __index
-- metamethod
mytable = {}
setmetatable(mytable, mytablemeta)
test = mytable.str1.str2.str3
for k, v in pairs(test) do
print(k, v)
end
It can't. Not without having a metatable on each of those tables.
mytable is a table. str1 is a different table. So you can do the same thing by doing this:
local temp = mytable.str1
temp.str2.str3
And as far as Lua is concerned, these are equivalent. Therefore, the only way to know what was done at each stage is to give all of them a special metatable. How you concatenate the different values into a table is something you'll have to investigate on your own.
As Nicol said, you cannot do that directly in Lua. However, by returning specially crafted tables, you can achieve a similar result to what you want. Take a look at AutomagicTables at the Lua-users Wiki for inspiration.

Resources