How does debug.traceback get its information? - lua

With the below code from the Lua demo page, I was trying to get the name of the function being pcalled.
function test()
local info = debug.getinfo(1);
for k, v in pairs(info) do
print(k, v);
end;
end;
pcall(function()
test();
end);
This was a success, as I received the following output, containing the name:
source =input
func function: 0x25a1830
nparams 0
short_src input
isvararg false
name test
namewhat global
istailcall false
linedefined 1
lastlinedefined 7
nups 1
currentline 2
what Lua
If I change the code to the following, I no longer get that information:
function test()
local info = debug.getinfo(1);
for k, v in pairs(info) do
print(k, v);
end;
end;
pcall(test);
The output is as follows:
func function: 0x21ee790
linedefined 1
nups 1
short_src input
namewhat
lastlinedefined 7
isvararg false
istailcall false
what Lua
source =input
currentline 2
nparams 0
If, however, I change the code to the following, I can obtain the name of the function passed to pcall:
function test()
local traceback = debug.traceback();
print(traceback);
end;
pcall(test);
With the output being as follows:
stack traceback:
input:2: in function 'test'
[C]: in function 'pcall'
input:7: in main chunk
[C]: in function 'pcall'
demo.lua:49: in main chunk
[C]: in ?
How does debug.traceback get this extra information, and using solely Lua is there a way to get it without extracting it from debug.traceback's return value?

debug.getinfo and debug.traceback get their info from various sources, some of them hacky. For instance, the function name is generally extracted from the source code of the calling function: whatever name the code used to look up the thing it called, that's what gets used as the name. (That's why your second code snippet didn't give you the name: pcall doesn't have Lua bytecode backing it up, so it can't tell you "test" unless there's a function in the middle to call it "test".) Lua functions do not have inherent names, any more than Lua integers do; a function is just another kind of value, which can be automatically assigned to a variable via some syntactic sugar.

Functions are values. Values don't have names.
Functions are not "declared" as in some other languages. A function value is created when a function definition is evaluated.
Debugging output is just trying to be helpful in simple cases by giving the name of a variable associated with calling the function value.

Related

Struggling with calling lua functions from the command line

I have the following code:
dofile(arg[1])
function1 = arg[2]
argument = arg[3]
returned = _G[function1](argument)
print(returned)
It is designed to take three command-line arguments and run a function from a file.
So, i run the command lua libs.lua "printStuff.lua" "printStuff" "\"Hello, World\"", and i always end up with this:
"Hello, World"
nil
I don't understand why i always get "nil".
Here are the contents of printstuff.lua:
function printStuff(stuff)
print(stuff)
end
That is to be expected. What's going on here:
You're executing the file specified by the first argument, printstuff.lua, which will leave a function printStuff in the global table _G.
You're indexing the global table with the second argument, printStuff, obtaining that function
You're calling the function you just obtained with the third command line argument, "Hello World!", as parameter, which prints it, and storing the result of that in the global variable returned. The function printStuff doesn't return anything (there's no return in there, and even if there was, print doesn't return anything either), so you're assigning nil to returned.
You're printing returned, which is nil
Side note: I'd use the vararg ... instead of the arg table for improved readability:
local file, func, param = ...
dofile(file); print(func(param))
Why not simply...
-- xlua.lua
-- Example: lua xlua.lua os date "%H:%M:%S"
-- Or: lua xlua.lua _G print "Hello World"
-- Or: lua xlua.lua dofile /path/to/someusefull.lua "Arg for someusefull.lua"
local result = _G[arg[1]][arg[2]](arg[3])
-- 5. Only put out whats not nil
if (result ~= nil) then
print(result)
end

Making local the _G variables & execute location

First doubt
For example, next can be stated as local very easily
local next = next
But how would it be with table.insert for example?
Making an anonymous function with table.insert inside on a local var would actually work?
Second doubt
Is it possible to know from where a function is being executed? This take us back to my first doubt, how can i ensure a _G variable is being executed locally
Really asking because besides default _G variables, i have few more added on my project
But how would it be with table.insert for example?
local table = table
how can i ensure a _G variable is being executed locally
It is still the same function value. You just added a local reference to it. Local variables can be looked up faster. You would have to call a function very often to really benefit from doing that.
This is opinionated but that opinion is shared among most programmers:
Don't waste time on premature optimization. Don't create local references for every global you encounter.
With load() you can give Lua code an own environment.
Normally (without that own environment) _G (5.1) or _ENV (since 5.3) is used.
Example you can play with...
> _VERSION
Lua 5.4
> load('do local tab, concat, insert = {}, concat, insert insert(tab, "Hello World!") return concat(tab) end', 'own_env', 't', {concat = table.concat, insert = table.insert})()
Hello World!
> load('do local tab, concat, insert = {}, concat, insert insert(tab, "Hello World!") return concat(tab) end', 'own_env', 't')()
[string "own_env"]:1: local 'insert' is not callable (a nil value)
stack traceback:
[string "own_env"]:1: in main chunk
(...tail calls...)
[C]: in ?
Source: https://www.lua.org/manual/5.4/manual.html#pdf-load

Lua strange behaviour with _ENV

Can anybody explain why lua 5.3.5 acts this way?
a="global"
local b="local"
function problem(_ENV)
a="fn_a"
b="fn_b"
end
problem{}
print(_VERSION)
print("a",a)
print("b",b)
--[[ https://www.lua.org/cgi-bin/demo output:
Lua 5.3
a global
b fn_b
]]
Why local variable can be changed after _ENV changed? Is it bug or feature?
Q: How to eliminate all upvalues?
A:
a="global"
local b="local"
-- load() actually eliminates all upvalues :-)
no_problem = assert(load[[
return function (_ENV)
a="fn_a"
b="fn_b"
end
]])()
no_problem{}
print(_VERSION)
print("a",a) --> a global
print("b",b) --> b local
You are creating upvalue with the following code:
local b="local"
function problem(_ENV)
b="fn_b"
end
During parsing of the function interpreter detects, that function refers to local variable from one of encompassing scopes that are visible from within the function and thus links it directly. Access to local variables precedes lookup of globals in the _ENV. If you put local b="local" after the function definition, it will not be altered by function calls.

Lua flexible function argument unpacking in local function

I am working on command handler that needs to work in two environments. Below is a a small part of the function I am working on, which I think captures the problem. At least, I get the error message I need to adress.
In the live environment, a Fibaro Home center 2, command sets given in the table should be executed one by one using fibaro:call, which takes 2-3 arguments, depending the call.
During development I instead use the print function to just print the commands that should have been issued.
function movementHandler(movementSendorId,onTable)
local offTable = offTable or {};
local onTable = onTable or {};
if (fibaro or {}).call then
function callFunc(...) ;
return fibaro:call(...);
end;
else
function callFunc(...)
print(unpack(arg));
end;
end;
if onTable ~= {} then
for i,command in pairs(onTable) do
callFunc(unpack(command));
end;
end;
end;
However, when I try this in the Lua command shell
> c= {}
> c[1] = {1,"turnOn"}
> c[2] = {1,"setValue",10}
> movementHandler(10,c,c)
, I get this output:
stdin:10: bad argument #1 to 'unpack' (table expected, got nil)
stack traceback:
[C]: in function 'unpack'
stdin:10: in function 'callFunc'
stdin:15: in function 'movementHandler'
stdin:1: in main chunk
[C]: in ?
What I am not understanding about how unpack works?
Automatic creation of the arg table for vararg functions was deprecated in Lua 5.1 and removed in Lua 5.2.
Use simply
function callFunc(...)
print(...)
end
If you need a table, use
function callFunc(...)
local arg={...}
print(unpack(arg))
end

Why is 'name' nil for debug.getinfo(1)

I'm trying to put together a lua testing framework that lets you know the function that had the problem, but when I switched from loadstring to _G, (I switched so my test harness could see the results of the function call) my functions started using 'nil' for the function name
Why can _G not detect the name of the current function in the following code? Also, how can I get the return results from loadstring (ie the 'false' from the blah call) or set the function name when using _G (ie. Tell the lua interpreter what the function name should be)?
function run_test(one, two)
if one ~= two then
print(debug.getinfo(2).name..' Failed')
end
end
function blah()
run_test(false, true)
return false
end
local fname = 'blah'
local status, result = pcall(_G[fname]) -- Outputs 'nil'; result is 'false'
local status, result = pcall(loadstring(fname..'()')) -- Outputs 'blah', result is 'nil'
The main thing I need is a way to call a function using a string of the function name, be able to see the function name inside the call (for test failures to point to the function that failed, like fname = 'blah' in the code above) and be able to get the return value
local fname = 'blah'
status, result = pcall(??Call fname somehow??)
assert(status)
assert(not result)
--stdout should be "blah Failed"
This is a limitation of the heuristics used by Lua to provide names for functions.
In Lua, all functions are anonymous. A given function can be the value of several variables: global, local, and table fields. The Lua debug system tries to find a reasonable name for a value based on where it came from by looking into the bytecode being executed.
Consider the simpler example
blah()
pcall(blah)
In the first call, the debug system sees that the function being called comes from the global blah and debug.getinfo(1).name gives the expected result, blah.
In the second call, the debug system sees that the function being called comes from the first argument to pcall but it does not look further to see where that argument came from, and debug.getinfo(1).name gives nil.
The same thing happens when you call _G[name](). All the debug system sees is a field of a table and the name of the field is too far off.
Try adding print(debug.traceback()) as the first line of blah to see another take on this explanation.

Resources