Reputation: 2023
I am trying to create a proc trace method. Means when script will use any proc it will print its procedure name and proceed. To do that I am following this method
rename proc _proc
_proc proc {nm params body} {
eval "_proc $nm \{$params\} \{
puts \"Enter proc $nm\";
puts \"Parameters: $params and body \" ;
$body;
puts \"Exit proc $nm\"\}"
}
proc abc { param1 param2 param3 } {
puts "$param1 and $param2 and $param3"
}
When I am calling proc abc
, it is giving output as
Enter proc abc
Parameters: param1 param2 param3 and body
a and b and c
Exit proc abc
Question: Why this is printing body also as i definition I want only parameters to print
Upvotes: 0
Views: 52
Reputation: 13252
There are many ways to write a replacement for the proc
command that allow tracing and introspection features to be injected. However, the best way to go about it is probably to use the trace
command to attach tracing hooks to a procedure, and let those hooks invoke info
commands to list things like parameter lists, procedure bodies etc.
Upvotes: 0
Reputation: 137567
That seems over-complicated to me. Let's get rid of the eval
and reduce the amount of quoting for starters. (Omitting the rest of your code for simplicity.)
_proc proc {nm params body} {
_proc $nm $params \
"[list puts "Enter proc $nm"];
[list puts "Parameters: $params and body "];
$body
[list puts "Exit proc $nm"]"
}
But that's not exactly what you want, is it? You want to print the actual parameters and not the formals. That's rather more complex.
_proc proc {nm params body} {
set cmd "[list puts "Enter proc $nm"];puts \"Parameters: "
foreach p $params {
append cmd "[lindex $p 0]=\$[lindex $p 0], "
}
append cmd " and body \";"
_proc $nm $params $cmd$body\;[list puts "Exit proc $nm"]
}
But even that will go wrong horribly once you start trying to have a meaningful result returned from the procedure. While you could do something horrific with catch
and return
to make it work (and it's easier in 8.5, and much easier with 8.6's try
…finally
), you want a different approach. You want execution traces.
_proc proc {nm params body} {
_proc $nm $params $body
trace add execution $nm enter [list track_entry $nm $params]
trace add execution $nm leave [list track_leave $nm]
}
_proc track_entry {nm params real args} {
puts "Enter proc $nm"
foreach formal $params actual [lrange $real 1 end] {
append p " [lindex $formal 0]=$actual,"
}
puts "Parameters:$p and body"
}
_proc track_leave {nm args} {
puts "Exit proc $nm"
}
If we try that, we see we get very informative output and yet we don't “disturb” the procedure's working:
% abc p d q Enter proc abc Parameters: param1=p, param2=d, param3=q, and body p and d and q Exit proc abc % info body abc puts "$param1 and $param2 and $param3"
Upvotes: 2