Unfortunately, it does not work for me.
When I enter:
% set ::errorLevel -1
% set ::errorStack {}
% trace add variable ::errorInfo write {
> set __n [ info level ]
> if { ( $__n > 0 ) && ( $__n != $::errorLevel ) } {
> set ::errorLevel $__n
> set __l [info level 0]
> lappend ::errorStack $__l
> }
> }
And make an errorneous test routine:
% proc e args {q $args}
% e q
invalid command name "q"
Which is correct. Now check the new errorStack:
% set errorStack
auto_load_index e
O.k., no parameters - well. So look to the traditional errorInfo:
% set errorInfo
invalid command name "::errorInfo"
So this breaks a lot.
This is tcl8.5.9 on windows 32 bit.
Thank you,
Harald
perhaps you mean something like this:
% set errorLevel -1
-1
% set errorStack {}
% trace add variable ::errorInfo write {apply {{varName element
operation} {
set level [info level];
if {($level > 0) && ($level != $::errorLevel)} {
set ::errorLevel $level;
lappend ::errorStack [info level -1];
}
}}}
% proc a {} {b a}
% proc b {a} {c $a b c}
% proc c {a b c} {d $a $b $c d}
% proc d {a b c d} {e $a $b $c $d e}
% proc e args {bumm $args}
% a
invalid command name "bumm"
% set errorStack
{e a b c d e} {d a b c d} {c a b c} {b a} a
% set errorInfo
invalid command name "bumm"
while executing
"bumm $args"
(procedure "e" line 1)
invoked from within
"e $a $b $c $d e"
(procedure "d" line 1)
invoked from within
"d $a $b $c d"
(procedure "c" line 1)
invoked from within
"c $a b c"
(procedure "b" line 1)
invoked from within
"b a"
(procedure "a" line 1)
invoked from within
"a"
Cheers,
Martin
P.S.: trace add variable needs a command accepting three arguments
(varName, element, operation).
Thanks for the fix Martin. Funnily, my old syntax worked until 8.5.7
at least. I was not aware of such incompatible syntactic evolutions...
Martin, can you please add a comment to the wiki page ?
But do keep the old syntax, because [apply] is fairly recent in Tcl
history ;-).
-Alex
Thank you Martin and Alexandre for the answers!
I took a look into the documentation of "trace add variable".
The arguments for the call are "name ops commandPrefix", where the
commandPrefix needs to be something accepting three arguments (or
more).
Here the paragraph about the context the commandPrefix is evaluated
in:
--- tcl man page: trace ---
CommandPrefix executes in the same context as the code that invoked
the traced operation: if the variable was accessed as part of a Tcl
procedure, then commandPrefix will have access to the same local
variables as code in the procedure. This context may be different than
the context in which the trace was created. If commandPrefix invokes a
procedure (which it normally does) then the procedure will have to use
upvar or uplevel if it wishes to access the traced variable. Note also
that name1 may not necessarily be the same as the name used to set the
trace on the variable; differences can occur if the access is made
through a variable defined with the upvar command.
--- tcl man page: trace ---
So, what is a valid commandPrefix accepting the arguments name1, name2
and operation?
Your script provided to the trace command does not "accept" arguments,
so I never thought it would work and would call this a bug, that is
now fixed.
Since tcl 8.0, the version I started seriously to work with, I
provided commands or procedures to the trace command and continued
this, since the rework of the trace command.
So - is it really needed to keep the not working example in the wiki
page?
Best regards,
Martin
On 7 Dez., 17:08, Alexandre Ferrieux <alexandre.ferri...@gmail.com>
wrote:
Oh you're right, and clearly I had mis-copy-pasted my code ;).
Just fixed the wiki page by ending the block with
list }
which is the traditional idiom to ignore appended args.
This way the code should work across many versions of Tcl, including
pre-[apply] ;-)
-Alex
maybee my test examples are stupid because I use them in interactive
mode, but for me, this is strange.
- take a fresh wish859
- paste the code from the wiki
- enter a test proc:
% proc e args {q {*}$args}
- invoke it
% e q
invalid command name "q"
- look on traditional errorInfo:
6 % set errorInfo
invalid command name "::errorInfo"
while executing
"::errorInfo {} write"
IMHO this error comes from the write trace
- Check errorStack
% set errorStack
auto_load_index {e q}
Ok, here is the autoloading. So try another proc:
% proc e2 args {expr 1/0}
% e2
divide by zero
% set errorInfo
invalid command name "::errorInfo"
while executing
"::errorInfo {} write"
% set errorStack
auto_load_index {e q}
Is this intended ?
Thank you,
Harald
Did you really paste the code from the wiki as is, with the last line
reading
list }
(note there's no end-of-line between 'list' and final brace, so that
argument concatenation generates 'list foo bar ...')
-Alex
Like on the wiki ? Yes, but:
On the wiki, the last line looks for me as:
<CODE>
list
}
</CODE>
The magic wiki is corrected to reflect this.
I would not mind if you could comment this trick on the wiki page.
The first thing I would do is to reformat the curly brace and this
would break the magic function.
I would also apreciate to have the later remark included in the
example.
My skills are not sufficient to at least understand what is happening.
I have tried to use "puts" to find out what happens but I think, the
"list }" issue always gave errorneous results.
Thank you,
Harald
Sorry, copypasta error again :(
Now we have this:
# the next line must end with the closing brace on the same line
# in order to consume the extra arguments at runtime.
list }
Is that satisfactory ?
-Alex
Absolutely ! Thank you,
Harald
There is the reload part by Martin Lemburg:
if {[string match {*while executing*} $::errorInfo] == 0} {
set ::errorLevel -1;
set ::errorStack [list];
}
I first found out the addressed issue: the traceBack is only filled
with the first error.
Then, the state variables must be reset to rework again.
I did not figure out where to put this code.
I have added a "puts" in the write event to find out, when there is
the text "while executing" in errorInfo - it is always in.
So I just tried to put it at the beginning - no effect.
If an unknown command is called, the first element is
"auto_load_index". Is there anything to do about it ?
Does this disabear if not in interactive mode ?
When I am a bit clearer, I may add some novice issues on the wiki
page.
Thank you,
Harald
Oh ! You're right again !
Apparently, at some point in time that smart idiom from Martin ceased
working.
Initially, there were two separate writes to ::errorInfo: one to store
the main error string, and one to add "while executing". Martin's code
detected the first, which is the ideal point for a reset. Now
"today" (would have to chase the critical version where this changed),
this is no longer the case, and ::errorInfo is initialized with both
strings in one single SetVar.
OK, so I reacted by updating the wiki page again:
if {![regexp {\n invoked from within\n} $::errorInfo]} {
set ::errorLevel -1;
set ::errorStack [list];
}
As you can see, this relies on detected the more robust "invoked from
within" connector (also with a regexp to allow for compiled RE
cacheing).
Obviously this can be beaten by "special cases", like [error "\n
invoked from within\n"], or some less frequent cases of connector.
Please feel free to expand the regexp with (...|...|...) when you find
the latter.
> If an unknown command is called, the first element is
> "auto_load_index". Is there anything to do about it ?
What's wrong with telling the truth ? ;-}
> Does this disabear if not in interactive mode ?
It even disappears on an interactive tclsh on unix ;-)
> When I am a bit clearer, I may add some novice issues on the wiki
> page.
Thank you for pushing things forward here. I admit letting it loose
since adding TIP 348 :)
-Alex
you have put your name below the wiki page so I knew this will lead
somewhere !
Thank you,
Harald