Чтобы поместить точку наблюдения в переменную, вы используете команду trace
. Вы можете получить расширенную информацию о контексте, в котором переменная была назначена с помощью команды info
, особенно подкоманд level
и frame
. (Последний доступен только с Tcl 8.5 и далее.)
Подобные вещи должны давать нужную информацию:
trace add variable x write peekLocation
proc peekLocation args {
puts "WRITTEN FROM >[info level -1]< CALL"
puts "DETAILS: [info frame -1]"
}
# Demonstration...
proc foobar {} {
global x
set x "jibber jabber"
}
foobar
Это не вполне работает, хотя; Вы можете легко найти, какая процедура работала во время обновления переменной, но где в этой процедуре произошло обновление, остается вне досягаемости. (Вместо этого вы видите вызов самого обратного вызова трассировки или, на одном уровне дальше по стеку, вызов процедуры, выполняющей манипуляции, ни один из которых не является таким полезным ...)
[РЕДАКТИРОВАТЬ]: Другой подход состоит в том, чтобы предположить, какая команда выполняет обновление (например, set
), и выполнить несколько jiggery-pokery так, чтобы info level
(единственная команда, которая может предоставить номер строки ) может делать правильные вещи:
rename set __orig_set;proc set args {doTrace;uplevel 1 [list __orig_set {*}$args]}
# Separate the probe from the instrumentation
proc doTrace {} {
puts [info frame -2]
}
Это работает. Также довольно легко распространить его на другие команды, которые выполняют установку переменных (например, [incr], [lappend], [lset]). Причудливый зонд это:
proc doTrace {} {
__orig_set f [info frame -2]
dict with f {
switch $type {
source {
puts "Write happened on line $line of file $file"
}
proc {
puts "Write happened on line $line of procedure $proc"
}
default {
puts "Write happened on line $line (command was >$cmd<)"
}
}
}
}
Не стесняйтесь экспериментировать!