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
Related
This is the sample test code.
s="\\command{sample execution}"
u=string.gsub(s,"\\(%b{})",print)
It works fine as print is global function. I defined function myprint as follows.
myprint = function(x,y)
return print(x,y)
end
Now the command u=string.gsub(s,"\\(%b{})",myprint) does not work. This is because the myprint is not global variable as the print is. So basic question that I want to ask is "How to assign function to global variable in Lua?"
You just need to write:
global_function_1 = function (arg)
-- body
end
or use the syntactic sugar alternative:
function global_function_2 (arg)
-- body
end
Make sure that the part in which you do that doesn't have a local variable with selected name. For instance none of the following functions are global:
local bar
local function foo (arg)
local zee
function arg () end
zee = function () end
function bar () end
end
Please note that I have totally ignored assigning to table members and ignored existence of _G and _ENV, and let's leave it this way.
I think that it is worth mentioning that the string.gsub (or really any function call) doesn't care whenever the function (or any argument) is local or whatever:
local str = "abc"
local function fn (x) print(x) end
string.gsub(str, "%a", fn)
outputs:
a
b
c
I have this code:
function test()
function awesome()
print("im awesome!")
end
function notawesome()
print("im not awesome.")
end
function notevenawesome()
print("im not even awesome...")
end
end
test().notawesome()
When I run this, the console prints
15: attempt to index a nil value
What I'm trying to do is call the function notawesome() within the function test(), how would I do that?
Your function is not returning anything (thus returning nil). Something like this should work:
function test()
function awesome()
print("im awesome!")
end
function notawesome()
print("im not awesome.")
end
function notevenawesome()
print("im not even awesome...")
end
result = {}
result["notawesome"] = notawesome
result["awesome"] = awesome
result["notevenawesome"] = notevenawesome
return result
end
test().notawesome()
#Axnyff explains what you might be trying to do. I'll explain what you did.
If you are familiar with other languages, please note that Lua does not have function declarations; It has function definitions, which are expressions that produce a function value when evaluated. Function definition statements, which you have used, are just shortcuts that implicitly include an assignment. See the manual.
When you run your code, a function definition is evaluated and the resulting function value is assigned to the variable test. Then the variable test is evaluated and its value is called as a function (and it is one).
When that function executes, three function definitions are evaluated and assigned to the variables awesome, notawesome, and notevenawesome, repsectively. It doesn't return anything.
So, when the result of calling test (nil) is indexed by the string "awesome", you get the error.
If you wanted to call the function value referred by the variable awesome, just do awesome().
If you want to achieve that instead to use the main function you can use an object:
test = {
awesome = (function()
return 'im awesome!'
end),
notawesome = (function()
return 'im not awesome.'
end),
notevenawesome = (function()
return 'im not even awesome...'
end)
}
To call your functions use this:
print(test.notawesome()) --> im not awesome.
function [TC]=Translate(T0,Base)
end
I know that Translate is a function and T0 and Base his parameter but what is [TC]?
Octave (and matlab) have a rather unique way of returning variables from functions. Instead of defining explicitly what to return from the function using a return keyword, they define from the outset which variables will be returned when the function exits, and octave simply looks for those variables by name at the time the function exits, and returns their values, whatever they may be by that point.
Your function may return nothing:
function returnsNothing();
disp('hello, I return nothing');
end
or it may return one output:
function Out = returnsOne(x)
Out = x+5
disp('This function will return the value of Out');
end
or it may return more than one outputs:
function [Out1, Out2] = returnsTwo(x)
Out1 = x+5;
Out2 = x+10;
end
You would call the last function from the octave terminal (or script) like this:
[a,b] = returnsTwo(5); % this will make a = 10 and b = 15
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
I have simple function in VBA and I would need to check whether or not it has been successfully performed. I do not know VBA much, so I have no idea whether or not its possible. I want to do something like this: bool X=MyFunction().
I am using VBA in the QTP descriptive programming. This does not work:
Function A as Boolean
A=true
End Function
It says: Expected statement
But I cannot see any return type in my method etc.
function MyFunction() as Boolean
.....
.....
MyFunction = True 'worked
end function
dim a as boolean = MyFunction()
In VBA, you set a function's return value by assign to a variable with the same name as the function:
Function MyFunc() as Boolean
MyFunc = True
End Function
I suspect you may be using VBScript instead of VBA? If that's the case then VBScript doesn't state Type
this will work in VBScript
dim test,b
test = 1
b=false
msgbox ("Calling proc before function test=" & test)
msgbox("Calling proc before function b=" & b)
b = A(test)
msgbox ("Calling proc after function test=" & test)
msgbox("Calling proc after function b=" & b)
Function A(test)
test = test +1
A=true
End Function
or in your example
Function A()
A=true
End Function
There is no real way to check if a function worked in VBA. You must decide for yourself whether your function was successful. For example:
Function AFunction() as Boolean
on error goto 1
MyFunc = True
AFunction = True
Exit Function
1
AFunction = False
End Function
The above would let you know if the function failed. If it fails, it goes to the label '1' and then returns false, otherwise, it returns true.
If it isn't an 'error' you are looking for, then you must decide if the data returned or supplied is proper. One way of doing this is to return a specific value [error-code] which represents a failure.
Well if you have access to your function declaration, you can set a bool return type for it and return true or false depending on the execution.
Once your function returns a bool, your code will work.