Bryan Oakley napisaĆ(a):
> set lineno 0
> foreach line [split $script \n] {
> if {![info exists command]} {
> set command $line
> } else {
> append command \n $line
> }
> incr lineno
> if {[info complete $command]} {
> if {[catch $command err]} {
> puts "error on line $lineno: $err"
> }
> unset command
> }
> }
That one's actually tricky.
(zoro) 55 % info complete "puts \\"
1
(zoro) 56 % eval "puts \\
x"
x
So this would not get parsed correctly. The other tricky thing is:
(zoro) 57 % eval "puts \\\\
x"
Since it's the opposite. The moral of the story is that \\ at the end of
a line are a PITA in this case. I think it is much safer to do info
complete and check for an even number of \ at the end (0 is also even
for me :-). But there's probably still some other issue (or issues) that
do not make it work... Anyway, here's "info complete on steroids" :-)
proc checkIfReallyComplete {line} {
if {![info complete $line]} {
return false
}
set count 0
while {[string index $line end-$count] == "\\"} {
incr count
}
if {$count % 2} {
return false
} else {
return true
}
}
> So, perhaps the answer to your question is "info complete" and "catch".
> That is, you can use [info complete] to know if a line or lines of
> user-entered text is a complete command, and "catch" to execute the
> command and to retrieve the result.
I no longer believe in [info complete]. Well, it would be great if Tcl
would have [info complete -strict] or something, that would actually
check what the interpreter would do. For now, I guess most people could
live with the equivalent above.
But, assuming he would have a proc called checkIfReallyComplete (or
something), then it would be much better to:
set realcode ""
set script [.text get 1.0 end-1c]
set lineno 0
foreach line [split $script \n] {
if {![info exists command]} {
set command $line
} else {
append command \n $line
}
incr lineno
if {[checkIfReallyComplete $command]} {
append realcode [list set ::lineNumber $lineno] \n $command \n
}
}
if {[catch $realcode]} {
puts "Error in $::lineNumber $::errorInfo"
}
And even better, this would allow storing the "debugable" version of the
script.
Then we would probably come up with a problem with control statements
like for/foreach/while/if and would have to emulate those (preferably at
"parser" level). Well then we will have custom control statements... (ie
expect command from expect or tcom::foreach). I think this is a messy
situation. Well, not to mention considering namespaces while parsing (ie :
namespace eval tcom {
foreach ....
}
is not quite obvious. Especially with the following "crude" code:
set ns tcom
namespace eval $ns {
foreach ....
}
Then there's metaprogramming ;-)
I wonder if an universal parser could be produced this way - one that
would return return something similar to command tree so that everyone
could debug it the way they want to (GUI, logging, whatever).
Just my 2 cents in this matter. If anybody wants to pursue this, I would
love to see the results. I wanted to, but got scared by the problems
above. Anyway, for a plain Tcl script, those problems do not really
exist :-) So just reparsing using info complete + for/foreach/while/if
would easily debug 90% of the scripts.
--
WK
Received on Sat Oct 15 03:53:42 2005