Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are
spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the
password reset link.
Entire forum
➜ MUSHclient
➜ Lua
➜ Nick Gammon's DebugFunction for Lua
Nick Gammon's DebugFunction for Lua
|
It is now over 60 days since the last post. This thread is closed.
Refresh page
Pages: 1 2
Posted by
| Dave K
(7 posts) Bio
|
Date
| Sat 17 Nov 2018 10:14 PM (UTC) Amended on Sat 17 Nov 2018 10:17 PM (UTC) by Dave K
|
Message
| This code proposed by Nick Gammon results in error. The assert is triggered because _G[f] is nil. Can anyone tell me why and how to fix this?
------------------------------
Posted by Nick Gammon Australia (21,841 posts) [Biography] bio Forum Administrator
Date Mon 07 May 2007 03:13 AM (UTC)
Amended on Mon 07 May 2007 05:00 AM (UTC) by Nick Gammon
Message
The code below illustrates how to make a special debugging version of any Lua function (including the MUSHclient world functions).
What it does is save the original function into a local variable, and then replace the function of that name in the global table (_G) with a debug version.
The debug version accepts any number of arguments (by using "..."), and then displays:
The name of the function that was called
Where it was called from (function name and line number)
A list of all the arguments which were sent to the function.
Then it calls the original function, passing any arguments that were sent to it.
It uses TraceOut to display this information, so to see it you need to turn Trace on (Game Menu -> Trace).
function DebugFunction (f)
assert (type (f) == "string" and type (_G [f]) == "function",
"DebugFunction must be called with a function name")
local old_f = _G [f] -- save original one for later
_G [f] = function (...) -- make new function
local t = debug.getinfo (2, "ln") -- get line and caller name
t.name = t.name or "<unknown place>"
TraceOut ("Function ", f, " called.") -- show name
TraceOut ("Called from ", t.name, " at line ", t.currentline) -- show caller
local n = select ("#", ...) -- number of arguments
if n == 0 then
TraceOut ("No arguments.")
else
for i = 1, n do -- show each argument
TraceOut ("Argument ", i, " = ", tostring ((select (i, ...))))
end -- for each argument
end -- have some arguments
old_f (...) -- call original function now
end -- debug version of the function
end -- DebugFunction
Now to use it, you call DebugFunction for each function you want to debug, passing the function name as an argument (you must get the spelling and capitalization exactly right):
DebugFunction ("ColourNote")
DebugFunction ("BroadcastPlugin")
This effectively replaces (in this example) ColourNote and BroadcastPlugin with debugging versions.
Now to test it:
function mytest ()
ColourNote ("red", "green", "hello, world") -- line 25
BroadcastPlugin (100, "some message") -- line 26
end -- mytest
mytest ()
Output
TRACE: Function ColourNote called.
TRACE: Called from mytest at line 25
TRACE: Argument 1 = red
TRACE: Argument 2 = green
TRACE: Argument 3 = hello, world
hello, world
TRACE: Function BroadcastPlugin called.
TRACE: Called from mytest at line 26
TRACE: Argument 1 = 100
TRACE: Argument 2 = some message
You can see from the trace output, that our debug version was called from "mytest" function, we are told the exact line number, and we are told the exact arguments.
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| Nick Gammon
Australia (23,120 posts) Bio
Forum Administrator |
Date
| Reply #1 on Sun 18 Nov 2018 06:03 AM (UTC) Amended on Sun 18 Nov 2018 06:07 AM (UTC) by Nick Gammon
|
Message
| |
Posted by
| Nick Gammon
Australia (23,120 posts) Bio
Forum Administrator |
Date
| Reply #2 on Sun 18 Nov 2018 06:11 AM (UTC) |
Message
|
Dave K said:
This code proposed by Nick Gammon results in error. The assert is triggered because _G[f] is nil. Can anyone tell me why and how to fix this?
I've just tested the code in the linked post and it works exactly how it did in 2007.
So instead of saying it "results in error" you need to post exactly what you did, and the exact error message you got.
Perhaps you misspelt the name of the function you were trying to test? Or it wasn't a Lua function? Without any details we are just guessing here. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| Dave K
(7 posts) Bio
|
Date
| Reply #3 on Sun 18 Nov 2018 07:43 AM (UTC) Amended on Sun 18 Nov 2018 07:58 AM (UTC) by Nick Gammon
|
Message
| Nick, My apologies. You are absolutely correct. I have copy & paste the code. The only thing i have added are the two print(type) lines. Which results in string for f and nil for _G[f]. So then the assert is triggered as you can see in the output. I am using Lua 5.1
-------------------------------------------------------------------------------
function DebugFunction (f)
print(type(f))
print(type(_G[f]))
assert (type (f) == "string" and type (_G [f]) == "function",
"DebugFunction must be called with a function name")
local old_f = _G [f] -- save original one for later
_G [f] = function (...) -- make new function
local t = debug.getinfo (2, "ln") -- get line and caller name
t.name = t.name or "<unknown place>"
TraceOut ("Function ", f, " called.") -- show name
TraceOut ("Called from ", t.name, " at line ", t.currentline) -- show caller
local n = select ("#", ...) -- number of arguments
if n == 0 then
TraceOut ("No arguments.")
else
for i = 1, n do -- show each argument
TraceOut ("Argument ", i, " = ", tostring ((select (i, ...))))
end -- for each argument
end -- have some arguments
old_f (...) -- call original function now
end -- debug version of the function
end -- DebugFunction
DebugFunction ("ColourNote")
DebugFunction ("BroadcastPlugin")
function mytest ()
ColourNote ("red", "green", "hello, world") -- line 25
BroadcastPlugin (100, "some message") -- line 26
end -- mytest
mytest ()
-------------------------------------------------------------
output:
Program completed in 1.09 seconds (pid: 12656).
"string"
"nil"
Nick.lua:5: DebugFunction must be called with a function name
stack traceback:
[C]: in function 'assert'
Nick.lua:5: in function 'DebugFunction'
Nick.lua:25: in main chunk
Debugging session completed (traced 0 instructions).
| Top |
|
Posted by
| Nick Gammon
Australia (23,120 posts) Bio
Forum Administrator |
Date
| Reply #4 on Sun 18 Nov 2018 08:01 AM (UTC) |
Message
|
Quote:
Nick.lua:5: DebugFunction must be called with a function name
Judging by the fact that you are running Nick.lua, you are not running this code inside MUSHclient. Therefore the functions ColourNote and BroadcastPlugin do not exist.
You need to test with some function that you are interested in debugging. This code is not intended to run "stand alone".
You will also find that TraceOut does not exist if you run from the command line. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| Dave K
(7 posts) Bio
|
Date
| Reply #5 on Sun 18 Nov 2018 07:06 PM (UTC) Amended on Mon 19 Nov 2018 09:34 PM (UTC) by Fiendish
|
Message
| Thanks again. I created the functions (dummy versions) and added them. Also replace traceout with print. It works well now. I have two minor issies.
1- the tostring ((select (i, ...))) doesn't work as the third paramter of the print statement. it does if I move it like so print (tostring ((select (i, ...))),"Argument ", i, " = ") I was wondering if you know why that is.
2- If I change the function test() with a table wrapping our two functions, it does not catch the table's name. Is there any way to catch the table's name if our functions are inside a table?
function DebugFunction (f)
assert (type (f) == "string" and type (_G [f]) == "function",
"DebugFunction must be called with a function name")
local old_f = _G [f] -- save original one for later
_G [f] = function (...) -- make new function
local t = debug.getinfo (2, "ln") -- get line and caller name
t.name = t.name or "<unknown place>"
print ("Function ", f, " called.") -- show name
print ("Called from ", t.name, " at line ", t.currentline) -- show caller
local n = select ("#", ...) -- number of arguments
print("number of args:", n)
if n == 0 then
print ("No arguments.")
else
for i = 1, n do -- show each argument
print ("Argument ", i, " = ",tostring ((select (i, ...))))
end -- for each argument
end -- have some arguments
old_f (...) -- call original function now
end -- debug version of the function
end -- DebugFunction
ColourNote = function(p1,p2,p3)
--print("What you sent is :",p1,p2,p3)
end
BroadcastPlugin = function(pr1,pr2)
--print("What you sent is :",pr1,pr2)
end
DebugFunction ("ColourNote")
DebugFunction ("BroadcastPlugin")
myTable = {1,2,3,
--function mytest ()
ColourNote ("red", "green", "hello, world") ,
BroadcastPlugin (100, "some message")
--end -- mytest
--mytest ()
}
| Top |
|
Posted by
| Fiendish
USA (2,533 posts) Bio
Global Moderator |
Date
| Reply #6 on Mon 19 Nov 2018 04:02 PM (UTC) Amended on Mon 19 Nov 2018 09:35 PM (UTC) by Fiendish
|
Message
|
Quote: he tostring ((select (i, ...))) doesn't work
"Doesn't work" is almost never sufficient information for debugging. Doesn't work in what way?
Also
|
To make your code more readable please use [code] tags as described here.
|
[EDIT] I've done it for you |
https://github.com/fiendish/aardwolfclientpackage | Top |
|
Posted by
| Dave K
(7 posts) Bio
|
Date
| Reply #7 on Mon 19 Nov 2018 05:29 PM (UTC) |
Message
| Thank you I have since resolved the tostring issue.
The only remaining issue is how to get it to recognize the function was called, is in a table. And what that tables name is.
Thank you. | Top |
|
Posted by
| Fiendish
USA (2,533 posts) Bio
Global Moderator |
Date
| Reply #8 on Mon 19 Nov 2018 09:37 PM (UTC) |
Message
|
Dave K said:
The only remaining issue is how to get it to recognize the function was called, is in a table. And what that tables name is.
This request is underspecified. You could be pointing to the functions from a million different tables. What then? |
https://github.com/fiendish/aardwolfclientpackage | Top |
|
Posted by
| Nick Gammon
Australia (23,120 posts) Bio
Forum Administrator |
Date
| Reply #9 on Tue 20 Nov 2018 02:31 AM (UTC) |
Message
| Can you give an example of what you are talking about? If you pass a table then only a reference to the table (the address) is passed. You could conceivably pass the name of a table, and then use _G[name] to find the table address.
That was why DebugFunction was called with a string (the function name) rather than the actual function. That way I can save the function name and then look up its address.
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| Dave K
(7 posts) Bio
|
Date
| Reply #10 on Tue 20 Nov 2018 03:40 PM (UTC) Amended on Tue 20 Nov 2018 11:36 PM (UTC) by Dave K
|
Message
| yes of course. Take your code for instance
function mytest ()
ColourNote ("red", "green", "hello, world") ,
BroadcastPlugin (100, "some message")
end -- mytest
mytest ()
and change it to this. Lets call this instance 1
myTable = -- assume this is on line 32
{1,2,3,
ColourNote ("red", "green", "hello, world") ,
BroadcastPlugin (100, "some message")
}
or even this ( instance 2 )
function mytest () -- assume this is on line 39
myTable = {1,2,3, -- assume this s on line 40
ColourNote ("red", "green", "hello, world") ,
BroadcastPlugin (100, "some message")
}
end -- mytest
mytest ()
I would like it to recognize that
in instance 1, the functions were called from inside a table called "myTable: on line 32
in instance 2, the functions were called from inside a function called mytest on line 40 which is in table myTable at line 39
essentially adding the ability to recognize where the functions reside (were called from) whether another function or a table. Because honestly majority of our functions are inside tables. so it would be a great help to know which table the called function belong to. | Top |
|
Posted by
| Fiendish
USA (2,533 posts) Bio
Global Moderator |
Date
| Reply #11 on Tue 20 Nov 2018 09:45 PM (UTC) Amended on Tue 20 Nov 2018 10:40 PM (UTC) by Fiendish
|
Message
|
Dave K said:
in instance 1, the functions were called from inside a table called "myTable: on line 32
This is false.
What you've done is call the function and then assign its returned value to a location in the table. But the function is not in the table or being called from inside the table.
Also, tables don't have names. Tables are unnamed structures in memory. You can assign variables to reference those structures, but the variable is not the table.
For instance:
A = {1, 2, 3}
B = A
B[2] = "b"
print(A[2]) -- this will print "b"
Is the table's name A or is it B?
Answer: neither. |
https://github.com/fiendish/aardwolfclientpackage | Top |
|
Posted by
| Fiendish
USA (2,533 posts) Bio
Global Moderator |
Date
| Reply #12 on Tue 20 Nov 2018 10:32 PM (UTC) Amended on Tue 20 Nov 2018 10:40 PM (UTC) by Fiendish
|
Message
| Further, tables don't store complex things. They reference them.
function my_function()
print("hi")
end
table_A = {
my_function
}
another_reference_to_my_function = table_A[1]
table_B = {
another_reference_to_my_function
}
print(table_B[1]) -- prints a memory address
print(table_A[1]) -- prints the same memory address
So which table is my function inside?
Answer: neither, because that's not how memory references work. |
https://github.com/fiendish/aardwolfclientpackage | Top |
|
Posted by
| Dave K
(7 posts) Bio
|
Date
| Reply #13 on Tue 20 Nov 2018 11:47 PM (UTC) Amended on Wed 21 Nov 2018 04:16 PM (UTC) by Dave K
|
Message
| Thank you for your reply. You have to forgive my ignorance. coming form C++ I am not sure what Lua can or cannot do.
So is there no way to track the execution of a lua script line by line? in order to produce a report such as below?
in Table abc
Called: function xyz
It has n parameters
Param 1: apples
Param 2: oranges
.
.
It has m returns
return 1: red
return 2: yellow
.
.
Called: function xyz2
It has n parameters
Param 1: pears
Param 2: bananas
.
.
It has m reruns
return 1: heavy
return 2: light
.
.
Exit Table abc
and so on....to the next table etc etc.
| Top |
|
Posted by
| Nick Gammon
Australia (23,120 posts) Bio
Forum Administrator |
Date
| Reply #14 on Wed 21 Nov 2018 04:52 AM (UTC) |
Message
| I think we are heading into X-Y problem land.
So is there no way to track the execution of a lua script line by line?
Why do you want to do this?
You are not really “in” a table. A table is a data structure. If you have some code that reads that table and calls functions in it you could report what you are doing as you traverse the table.
There is some debugging stuff built into Lua.
As Fiendish points out, this code isn’t really going to do anything useful:
This makes a table “myTable” which will probably have something like this actually in it:
That is because you are storing the results of two function calls in that table. I don’t see how that is useful.
The code I presented earlier makes an intermediate function which is supposed to help you track wanted functions. In other words, if you are tracking “ColourNote” it replaces ColourNote with another function which displays that you have called ColourNote and its arguments, and then calls the real (saved) ColourNote.
This concept on its own should solve your problem, except I don’t think Fiendish nor I understand exactly what your problem is. This talk of tables is confusing in this context.
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).
To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.
42,780 views.
This is page 1, subject is 2 pages long: 1 2
It is now over 60 days since the last post. This thread is closed.
Refresh page
top