Lua return from function problem - function

I'm trying to parse some xml files with lua and
I'm stuck on this function:
function get_node_by_id (xml, nodeId)
for i=1, #xml, 1 do
if get_attr_by_name(xml[i], 'Id') == nodeId then
print ("TRUEEEEE", i, xml[i])
return xml[i]
else
get_node_by_id(xml[i], nodeId)
end
end
end
The problem is that print("TRUEEEEE", i, xml[i]) works, but it returns nil in the next line return xml[i].
What am I doing wrong?

You are calling the function recursively, but only provide a single return. If you happen to find the node you are looking for in second level, you only return the value to first level, which doesn't do anything with it.
Maybe you want something like this (untested code):
function get_node_by_id (xml, nodeId)
for i=1, #xml, 1 do
if get_attr_by_name(xml[i], 'Id') == nodeId then
print ("TRUEEEEE", i, xml[i])
return xml[i]
else
local node = get_node_by_id(xml[i], nodeId)
if node then return node end
end
end
end

I think you're missing a return in the else block:
return get_node_by_id(xml[i], nodeId)

Related

understanding how a lua function does work?

I have a HTML project that uses mutiple lua scripts , I have big issue unterstanding the functionality of one function ( I'm new to lua) :
........................
all the requires have been done and the paths are also defined
local fs = require "lfs"
local const = {}
for num = 1, 14 do
const[num] = assert(
dofile (const_path .. mkfilename(num)),
"Failed to load constant configuration ".. num ..".")
end
local function file_number() --this is the function that causes me a headach
local ci, co, num = ipairs(const)-- when I print num is 0 and ci,co are nil
local vi, vo, _ = fs.dir(virt_path)-- what does _ mean here ?
local function vix(o)
local file = vi(o)
if file == nil then return nil end
local number = file:match("^(%d+).lua$")
if number == nil then return vix(o) end
return tonumber(number)
end
local function iter(o, num)
return ci(o.co, num) or vix(o.vo, num)---where is ci defined or impplemented
end
return iter, {co=co, vo=vo}, num-- what 's the return value here ?
end
the function works but I still don't understand why and how, I 'll be greatfull for any hint.
_ is conventionally a throw-away variable.
In this case though it serves no purpose and could just as easily be left out entirely.
ci should be a function and co should be a table there.
Similarly (though I can't say for sure about vo) for vi and vo.
That function is constructing its own iterator using the iterator functions and state returns from the ipairs and fs.dir functions.
The line return iter, {co=co, vo=vo}, num is returning an interator function, a table for state, and the initial loop variable (0 from the initial ipairs call).
When used in a loop that will loop over the values from ci and vix.

Composing two functions in lua

I just started learning lua, so what I'm asking might be impossible.
Now, I have a method that accepts a function:
function adjust_focused_window(fn)
local win = window.focusedwindow()
local winframe = win:frame()
local screenrect = win:screen():frame()
local f, s = fn(winframe, screenrect)
win:setframe(f)
end
I have several functions that accept these frames and rectangles (showing just one):
function full_height(winframe, screenrect)
print ("called full_height for " .. tostring(winframe))
local f = {
x = winframe.x,
y = screenrect.y,
w = winframe.w,
h = screenrect.h,
}
return f, screenrect
end
Then, I can do the following:
hotkey.bind(scmdalt, '-', function() adjust_focused_window(full_width) end)
Now, how could I compose several functions to adjust_focused_window, without changing it's definition. Something like:
hotkey.bind(scmdalt, '=', function() adjust_focused_window(compose(full_width, full_height)) end)
where compose2 would return a function that accepts the same parameters as full_width and full_height, and internally does something like:
full_height(full_width(...))
As mentioned in the comments, to chain two functions together you can just do:
function compose(f1, f2)
return function(...) return f1(f2(...)) end
end
But what if you want to connect more than 2 functions together? You might ask, is it possible to 'compose' an arbitrary number of functions together?
The answer is a definite yes -- below I show 3 different approaches for implementing this plus a quick summary of their consequences.
Iterative Table approach
The idea here is to call each function in the list one after the other in turn. While doing so, you save the returned results from the previous call into a table and you unpack that table and pass it into the next call.
function compose1(...)
local fnchain = check_functions {...}
return function(...)
local args = {...}
for _, fn in ipairs(fnchain) do
args = {fn(unpack(args))}
end
return unpack(args)
end
end
The check_functions helper above just checks that the stuff passed in are indeed functions -- raises an error if not. Implementation omitted for brevity.
+: Reasonably straight-forward approach. Probably what you'd come up with on a first attempt.
-: Not very efficient on resources. A lot of garbage tables to store results between calls. You also have to deal with packing and unpacking the results.
Y-Combinator Pattern
The key insight here is that even though the functions we're calling isn't recursive, it can be made recursive by piggy-backing it on a recursive function.
function compose2(...)
local fnchain = check_functions {...}
local function recurse(i, ...)
if i == #fnchain then return fnchain[i](...) end
return recurse(i + 1, fnchain[i](...))
end
return function(...) return recurse(1, ...) end
end
+: Doesn't create extra temporary tables like above. Carefully written to be tail-recursive -- that means no extra stack space needed for calls to long function chains. There's a certain elegance to it.
Meta-script generation
With this last approach, you use a lua function that actually generates the exact lua code that performs the function call chain desired.
function compose3(...)
local luacode =
[[
return function(%s)
return function(...)
return %s
end
end
]]
local paramtable = {}
local fcount = select('#', ...)
for i = 1, fcount do
table.insert(paramtable, "P" .. i)
end
local paramcode = table.concat(paramtable, ",")
local callcode = table.concat(paramtable, "(") ..
"(...)" .. string.rep(')', fcount - 1)
luacode = luacode:format(paramcode, callcode)
return loadstring(luacode)()(...)
end
The loadstring(luacode)()(...) probably needs some explaining. Here I chose to encode the function chain as parameter names (P1, P2, P3 etc.) in the generated script. The extra () parenthesis is there to 'unwrap' the nested functions so the inner most function is what's returned. The P1, P2, P3 ... Pn parameters become captured upvalues for each of the functions in the chain eg.
function(...)
return P1(P2(P3(...)))
end
Note, you could also have done this using setfenv but I chose this route just to avoid the breaking change between lua 5.1 and 5.2 on how function environments are set.
+: Avoids extra intermediate tables like approach #2. Doesn't abuse the stack.
-: Needs an extra byte-code compile step.
You can iterate through the passed functions, successively invoking the next function in the chain with the results from the previous.
function module._compose(...)
local n = select('#', ...)
local args = { n = n, ... }
local currFn = nil
for _, nextFn in ipairs(args) do
if type(nextFn) == 'function' then
if currFn == nil then
currFn = nextFn
else
currFn = (function(prev, next)
return function(...)
return next(prev(...))
end
end)(currFn, nextFn)
end
end
end
return currFn
end
Note the use of Immediately Invoked Function Expressions above, which allow the re-used function variables to not invoke an infinite recursive loop, which happens in the following code:
function module._compose(...)
local n = select('#', ...)
local args = { n = n, ... }
local currFn = nil
for _, nextFn in ipairs(args) do
if type(nextFn) == 'function' then
if currFn == nil then
currFn = nextFn
else
currFn = function(...)
return nextFn(currFn(...)) -- this will loop forever, due to closure
end
end
end
end
return currFn
end
Although Lua doesn't support ternary operators, short-circuit evaluation can be used to remove the inner if statement:
function module.compose(...)
local n = select('#', ...)
local args = { n = n, ... }
local currFn = nil
for _, nextFn in ipairs(args) do
if type(nextFn) == 'function' then
currFn = currFn and (function(prev, next)
return function(...)
return next(prev(...))
end
end)(currFn, nextFn) or nextFn
end
end
return currFn
end

Getting variable from a function

function isEven(x)
print("Checking if "..x.." is even.\nWill return state as 1 if true.")
if math.fmod(x, 2) == 0 then
state = 1
end
return state
end
I know that I can just run isEven and then use the state variable. But is there a way to do it in one line?
Like isEven(8).state?
Any and all help is appreciated.
As Egor said in a comment, this is precisely what return values are meant to do. When you see a function call in your code, such as isEven(8), it evaluates into that function's return value.
function isEven(x)
print("Checking if "..x.." is even")
return (math.fmod(x, 2) == 0)
end
print( isEven(8) )
print( isEven(7) )
if isEven(8) then
print("a")
else
print("b")
end
Finally, I would just like to point out a couple of things about the isEven function: First of all if you want you could use the % operator instead of math.fmod. Secondly, in the example I used the function returns a boolean value (true or false) instead of a number (0 or 1).

lua post hooking a function

I found one topic that's about post hooking, but I don't think it's the same thing as I want to accomplish. topic i found
What I need is the following:
local someBoolean = false
function doSomething() -- this is the function used in __index in a proxy table
someBoolean = true
return aFunction -- this is function that we can NOT alter
end
I need to ble able to run the code "someBoolean = false" after the return... (yes, I know that's not supposed to happen :p) considering aFunction may contain other functions itself, I want someBoolean to be true for the entire scope of aFunction, but after that, it HAS to be turned back to false
I'm sorry if I didn't manage to explain it well enough. Copy pasting the relevant code of my actual project would be way too large, and I don't want to waste your time.
I've been stuck on this for a while now, and I just can't seem to figure it out...
(edit: I can't just put someBoolean = false after the function, because the function is actually an __index function on a proxy table)
edit: relevent piece of code. I hope it's a bit clear
local function objectProxyDelegate(t, key)
if not done then -- done = true when our object is fully initialised
return cls[key] -- cls is the class, newinst is the new instance (duh...)
end
print("trying to delegate " .. key)
if accessTable.public[key] then
print(key .. " passed the test")
objectScope = true
if accessTable.static[key] then -- static function. return the static one
return cls[key] -- we need to somehow set objectScope back to false after this, otherwise we'll keep overriding protected/private functions
else
return newinst[key]
end
elseif objectScope then
print("overridden protected/private")
return cls[key]
end
if accessTable.private[key] then
error ("This function is not visible. (private)", 2)
elseif accessTable.protected[key] then
error ("This function is not visible to an instance. (protected)", 2)
else
error ("The function " .. key .. " doesn't exiist in " .. newinst:getType(), 2) -- den deze...
end
end
Since you need to return a function (rather than evaluate a function) you can create a proxy for the aFunction and return that instead. Here's how it could work (with a bunch of code taken from the solution by Nicol Bolas):
local someBoolean = false
function doSomething(...) -- this is the function used in __index in a proxy table
someBoolean = true
-- Return a proxy function instead of aFunction
return function(...)
local rets = { aFunction(...) }
someBoolean = false
return table.unpack(rets)
end
end
You cannot execute code after a return statement. The correct answer is to call the function, catch the return values, set the variable, and then return the return values. For example:
local someBoolean = false
function doSomething(...) -- this is the function used in __index in a proxy table
someBoolean = true
local rets = { aFunction(...) } -- this is function that we can NOT alter
someBoolean = false
return table.unpack(rets)
end

Lua - find out calling function

In Lua, is it possible to know which function has called the current function.
For instance
function a()
get_calling_function() --Should print function b
end
function b()
a()
end
Is something like this possible?
Does the debug library have such functionality?
You could use debug.traceback():
function a()
print(debug.traceback())
end
function b()
a()
end
b()
which would print:
stack traceback:
./test.lua:45: in function 'a'
./test.lua:50: in function 'b'
./test.lua:53: in main chunk
[C]: in ?
you can use debug.sethook() to set up a hook that gets called each time certain special events happen in lua. it can be useful for things like this.
local debugInfo = { caller = nil, callee = nil }
function hook()
local info = debug.getinfo(2)
if info == nil then
debugInfo.callee = nil
return
end
-- we only want to watch lua function calls (not C functions)
if info.what ~= "Lua" then
debugInfo.callee = "C function"
return
end
debugInfo.caller = debugInfo.callee
debugInfo.callee = info.name
end
debug.sethook(hook, "c")
function caller1()
if debugInfo.caller ~= nil and debugInfo.callee ~= nil then
msg = debugInfo.callee.. " was called by ".. debugInfo.caller.. "!"
print(msg)
end
end
function caller2()
caller1()
end
caller2()
this prints 'caller1 was called from caller2!'
debug.sethook can handle 3 different characters in the second parameter so you can let it know when to notify you. 'c' means call your hook function any time a function is called in lua, 'r' means call your hook function every time a function returns in lua, and 'l' means call your hook function whenever lua processes a new line of code.
you could set this up to build your own custom stack trace if you really wanted to, and you could also use debug.getlocal() within your hook to even try to work out what arguments were passed to your called function.
edit for lhf. this is actually a much simpler way of doing what you're asking, if you don't need to track this and just need to know the context of how the function was called.
function caller1()
local current_func = debug.getinfo(1)
local calling_func = debug.getinfo(2)
print(current_func.name.. " was called by ".. calling_func.name.. "!")
end
function caller2()
caller1()
end