Good day, I'm trying to understand a little more NSE scripts that are based on Lua, but there is something that I can't understand related to syntax when using functions as elements from a table. I'm going to show parts of the script nmap/scripts/broadcast-rip-discver.nse where I'm getting lost:
RIPv2 = {
-- The Request class contains functions to build a RIPv2 Request
Request = {
-- Creates a new Request instance
--
-- #param command number containing the RIPv2 Command to use
-- #return o instance of request
-- code ommitted (give values to the table o)
setmetatable(o, self)
self.__index = self
return o
end,
-- Converts the whole request to a string
__tostring = function(self)
--- -- code ommitted ( Override the metafunction __tostring)
return data
end,
},
-- The Response class contains code needed to parse a RIPv2 response
Response = {
-- Creates a new Response instance based on raw socket data
--
-- #param data string containing the raw socket response
-- #return o Response instance
new = function(self, data)
local o = { data = data }
-- code ommitted (Read from data and pass values to o)
setmetatable(o, self)
self.__index = self
return o
end,
}
}
And from the "action" part of the script we have a use like this
local rip = RIPv2.Request:new(RIPv2.Command.Request)
local response = RIPv2.Response:new(data) -- Data has been already give a value
I understand that is "similar" to create a new instance of the Table RIPv2 for those two lines. As all the function are inside of a table (that is not a class because Lua only have basic tools for make things similar but no the same to class) so the "self" argument it's mandatory for Lua have a idea to where place that.
But what I can't understand it's why try to override functions from the table RIPv2 to the table o, I mean the lines what objective has?:
setmetatable(o, self) )
I understand that the variable table o could have now the same functions that RIPv2 together his own values but this part make me crazy and I can't find a straight answer at Nmap's Forum.
P.d. which would be the difference to declare RiPv2 with "local" (Be sure that is not a Global variable)
As all the function are inside of a table so the "self" argument it's mandatory for Lua have a idea to where place that.
All the functions aren't necessarily part of the table. A metatable allows you to specify that lookups in table a can resolve to lookups in table b, and that's exactly what's being done here.
But what I can't understand it's why try to override functions from the table RIPv2 to the table o, I mean the lines what objective has?: setmetatable(o, self) )
o is an instance of a class, it contains only the instance data. The methods are stored in class objects Request or Response. The metatable allows attempts to index o to resolve via the class object.
See the Programming in Lua chapter on classes.
Related
I understand how to stack functions when creating a new table from the beginning like so :
Test:newNumber(5):add5():add5() --create a Number{} with Number.Num=5 then add to self.num
but im having trouble passing in previously existing tables as so:
function EnemyBase:isStandingOver( Object )
local o = Object
for k , v in pairs(Creature_Bases) do
if (o.x and o.y are over v.x and v.y) then
setmetatable( Creature_Bases[k] , self )
self.__index = self
return Creature_Bases[k]
end
end
end
function EnemyBase:changeSprite()
self.Sprite = self.SpriteTest
end
function ManageEnemies()
for k,v in pairs(Enemies) do
if EnemyBase:isStandingOver( Enemies[k] ) ~= nil then
EnemyBase:isStandingOver( Enemies[k] ):changeSprite()
end
end
end
I know ill need to create a meta method table with the __index pointing to self at some point but i don't know when.
Let's first understand what self is.
function a:b() end is syntactic sugar for function a.b(self) end
A function defined like that has a parameter self.
Function call a:b() is syntactic sugar for a:b(a)
A function called like that always has a as its first argument which inside the function ends up as parameter self.
So if you have defined a function like that, you have a very simple way to access table a through self from within that function without explicitly using reference a. This comes in handy if you want to do OOP in Lua.
Then we have to understand what the __index metamethod is.
__index: The indexing access operation table[key]. This event happens when table is not a table or when key is not present in table. The
metavalue is looked up in the metatable of table.
The metavalue for this event can be either a function, a table, or any
value with an __index metavalue. If it is a function, it is called
with table and key as arguments, and the result of the call (adjusted
to one value) is the result of the operation. Otherwise, the final
result is the result of indexing this metavalue with key. This
indexing is regular, not raw, and therefore can trigger another
__index metavalue.
Let's use both of it in a simple constructor:
MyClass = {}
function MyClass:New(name)
local instance = setmetatable({}, self)
self.__index = self
instance.name = name
return instance
end
function MyClass:SayName()
print("my name is " .. self.name)
end
If we now do this:
local myFirstInstance = MyClass:New("John")
local mySecondInstance = MyClass:New("Bob")
myFirstInstance:SayName()
mySecondInstance:SayName()
what's going to happen?
We know MyClass:New() is equivalent to MyClass.New(MyClass). So in our contructor self refers to MyClass.
local instance = setmetatable({}, self) creates a new table and sets self which is MyClass as its metatable.
self.__index = self set's MyClass as the __index metavalue of itself.
The name is stored in each instance and the instance is returned.
Now if you call myFirstInstance:SayName(), Lua will look up myFirstIntance["SayName"]. It won't find anything. So it will check wether table myFirstInstance has a metatable and if so, if there is a __index metavalue. There is. getmetatable(myFirstInstance).__index is MyClass so it will now actually call MyClass.SayName(myFirstInstance). So in the end, both instances will print their own name even though they do not even implement a SayName function. And MyClass.SayName prints both instances names without knowing even knowing the instances or even their names.
im learning lua and got to metatable part, in this example
local tb = {}
local meta = {}
function tb.new(s)
local super = {}
super.s = s
setmetatable(super,meta)
return super
end
function tb.add(s1,s2)
return s1.s..s2.s
end
meta.__add = tb.add
f= tb.new("W")
t= tb.new("E")
print(f+t)
in this part
function tb.add(s1,s2)
return s1.s..s2.s
end
how are values from super.s passed to tb.add function. i noticed that the variable s in s1.s and s2.s in return s1.s..s2.s seems to be the link between tb.new and tb.add.
and in this part
f= tb.new("W")
t= tb.new("E")
print(f+t)
when compiler gets to f+t i think this function is called first f= tb.new("W") in this function right now there is no s2 so it should be nil how did return s1.s..s2.s happen?
Your code is missing a table tb. Otherwise it results in an error for indexing a nil value.
Your code creates two table values with a field s = "E" and s = "W" respectively. Both have share the same metatable meta that implements the __add metamethod.
From the Lua 5.4 Reference Manuual 2.4 - Metatables and Metamethods
Every value in Lua can have a metatable. This metatable is an ordinary
Lua table that defines the behavior of the original value under
certain events. You can change several aspects of the behavior of a
value by setting specific fields in its metatable. For instance, when
a non-numeric value is the operand of an addition, Lua checks for a
function in the field __add of the value's metatable. If it finds one,
Lua calls this function to perform the addition.
So for f+t will call meta._add(f, t) which returns f.s..t.s
tb.new basically just creates a new table and returns it, so in this code:
f= tb.new("W")
t= tb.new("E")
... f and t are newly created tables, each with an s field and both with the same metatable.
The interpreter automatically calls meta.__add when it sees f+t and passes both operands as arguments. tb.add has two parameters and assumes both of them have an s field which is a string, so that all checks out perfectly. If t was not a table with an s field, then you would be in trouble.
In other words, tb.new does not pass s to tb.add. tb.new stores s inside the new table, and tb.add retrieves that value from its parameters.
As commented by #lhf and answered by #Piglet the code is not working as is.
So here is a corrected version that uses/show new Lua 5.4 warn().
It can be used for debugging because #on and #off let you control the output.
Here it is...
if warn==nil then warn=print else warn('#on') end
local meta={}
local tb={}
function tb.new(s)
warn('tb.new("'..s..'")')
local super={}
super.s=s
setmetatable(super,meta)
return super
end
function tb.add(s1,s2)
warn('__add('..tostring(s1)..', '..tostring(s2)..')')
return s1.s..s2.s
end
meta.__add=tb.add
f=tb.new("W")
t=tb.new("E")
print('Print: ',f+t)
Output is...
Lua warning: tb.new("W")
Lua warning: tb.new("E")
Lua warning: __add(table: 0x5661f510, table: 0x5661f580)
Print: WE
( On earlier Lua versions than 5.4 print() is used instead of warn() )
I want to lock the access of a table content in Lua 4.01.
Unfortunately I can't upgrade to Lua 5.xx.
I was thinking to use tag method (old metatable/metamethod mechanism of Lua) but it is still possible to traverse the table without triggering tagmethods using for loop (for ie,e in table do ...).
It's like for statement uses rawget to access the table content.
Is there a way to lock the access?
I know it would be possible using the C API but it's not really possible for the end-user.
Thanks
Using a table as un upvalue is a way to control data visibility. See Visibility and Upvalues in the Lua 4.0 Reference Manual.
You maintain your data in a table local to a function. That table can’t be seen outside of that function.
An example:
function a()
local t = {data = 123}
return function()
print(t.data)
end
end
Then:
b = a()
b() -- prints “123”
Bad practice here to just use letters for function names, but it gets the point across: b is just the table returned from calling a. But this b, when called, prints the data stored in a’s local table t. There is no other way to access t, so in this way you can control table access. Add more functionality (setters, getters, other logic) to a’s return table to control access.
Another Example
Showing getter and setter access:
function a()
local t = {data = nil}
local function set(data)
t.data = data
end
local function get()
return t.data
end
return {
set = set,
get = get
}
end
b = a()
b.set("abc")
print(b.get())
b.set(123)
print(b.get())
This prints:
abc
123
I want to add some methods or properties to a lua object witch metadata was created by C API. I can't add property in normal way, for example:
local foo = libc.new()
foo.bar = "hello"
it say:
Failed to run script: attempt to index a libc_meta value (local 'foo')
So I think maybe need to modify metatable, so I change my code:
local foo = libc.new()
local mt = getmetatable(foo)
foo[bar] = "hello"
setmetable(foo, mt)
Unfortunately, it still doesn't work.
Failed to run script: bad argument #1 to 'setmetatable' (table expected, got libc_meta)
So how can I add methods or properties to this 'foo'?
BTW, c code is here:
static int libc_new(lua_State *L) {
...
lua_lib_space *libc = lua_newuserdata(L, sizeof(*libc));
libc->L = L;
libc->cb_enter = cb_enter;
libc->cb_leave = cb_leave;
luaL_getmetatable(L, "libc_meta");
lua_setmetatable(L, -2);
lib_space *lib = lib_new(enter, leave, libc);
libc->space = lib;
return 1;
}
Userdata is meant to be created by C, manipulated by C code, and for only the purposes that C code intends. Lua can talk to it, but only in the ways that C allows it to. As such, while userdata can have a metatable (and those metamethods are the only way Lua can "directly" interact with the userdata), only C functions (and the debug library, but that's cheating) can directly manipulate that metatable. Lua is an embedded language, and C has primacy; if some C library wants to shut you out, it can.
What you can do is take the userdata and stick it in a table of your own, then give that table a metatable. In your __index metamethod, if you have an override or new method for a particular key, then you forward the accesses to that. Otherwise, it will just access the stored userdata.
However, if what you get in the userdata is a function, then you may have a problem. See, most userdata functions take the userdata as a parameter; indeed, most are meant to be called via "ud:func_name(params). But if thatud` is actually the table wrapper, then the first parameter passed to the function will be the wrapper, not the userdata itself.
That poses a problem. When the thing you get from the userdata is a function, you would need to return a wrapper for that function which goes through the parameters and converts any references to the wrapper table into the actual userdata.
Note that this question is about pure Lua. I do not have access to any module or the C side. Additionally, I can not use the IO, the OS or the debug library.
What I'm trying to make is a function that receives, as parameters:
a number that is an ammount of second
a callable value
By 'a callable value', I mean a value that can be called. This can be:
a function
a table with a metatable that allows calling (through a __call metamethod)
Here's an example of a callable table:
local t = {}
setmetatable(t, {
__call = function() print("Hi.") end
})
print(type(t)) --> table
t() --> Hi.
Here's the function:
function delay(seconds, func)
-- The second parameter is called 'func', but it can be anything that is callable.
coroutine.wrap(function()
wait(seconds) -- This function is defined elsewhere. It waits the ammount of time, in seconds, that it is told to.
func() -- Calls the function/table.
end)()
end
But I have a problem. I want the function to throw an error if the parameter 'func' is not callable.
I can check if it is a function. But what if it is a table with a metatable that allows calling?
If the metatable of the table is not protected by a __metatable field, then, I can check the metatable to know if it is callable, but, otherwise, how would I do it?
Note that I have also thought about trying to call the 'func' parameter with pcall, to check if it is callable, but to do that, I need to call it prematurely.
Basically, here's the problem: I need to know if a function/table is callable, but without trying to call it.
In general, if the metatable does not want you to be able to get it (by defining __metatable to being something special), then you're not going to get it. Not from Lua.
However, if you want to cheat, you can always use debug.getmetatable, which will return the metatable associated with that object.
You don't have to prematurely call anything with pcall. Observe:
pcall(function(...) return PossibleFunction(...) end, <insert arguments here>)
function iscallable(x)
if type(x) == 'function' then
return true
elseif type(x) == 'table' then
-- It would be elegant and quick to say
-- `return iscallable(debug.getmetatable(x))`
-- but that is actually not quite correct
-- (at least in my experiments), since it appears
-- that the `__call` metamethod must be a *function* value
-- (and not some table that has been made callable)
local mt = debug.getmetatable(x)
return type(mt) == "table" and type(mt.__call) == "function"
else
return false
end
end
return iscallable
Then you can do
> = iscallable(function() end)
true
> = iscallable({})
false
> = iscallable()
false
> = iscallable(nil)
false
> x = {}
> setmetatable(x, {__call=function() end})
> = iscallable(x)
true
If you don't have access to the debug library, then you may have trouble being totally accurate since you can mess with metatables. You could use pcall but its hard to separate out the errors properly. Even if you search for a particular error string as in the other answer here, that might be because of something inside the function being called not being callable, not this particular value not being callable, if that makes sense.
This attempt at refining Nicol's answer still has the problem that it needs to call the table, but it tells whether a supplied table actually was callable or not. Even if the table was callable, pcall() will return false if there is an error caused during the execution of the __call() metamethod.
local result = {pcall(PossibleFunction, ...)}
if not result[1] then
if result[2]:match"^attempt to call" then
error("The provided value is not callable.")
else
-- Table was callable but failed. Just hand on the error.
error(result[2])
end
end
-- Do something with the results:
for i = 2, #result do
print(result[i])
end
Checking the error message in this way however does not feel very "clean" (what if the used Lua interpreter was e.g. modified with localized error messages?).