[PYK] 2015-11-08: '''procstep''' is a drop-in replacement for `[proc]` that evaluates one command of a procedure body at at time, and provides one hook to inspect and manipulate the command before it is evaluated, and another to react to `[return]` codes. It requires [cmdSplit%|%scriptSplit] and [cmdSplit%|%nocomments]. These commands are also available as `[ycl%|%ycl proc tcl step]`. ====== ::tcl::proc proc {name args body} {$ ::uplevel [::list ::tcl::proc $name $args [::list apply [::list args [$ ::string map [::list {${body}} [::list $body]] {$ ::foreach command [::scriptSplit ${body}] {$ set status [$ ::catch [::list ::uplevel [::cmdhandler [$ namespace current] $command]] cres copts]$ ::if {$status} {$ uplevel [::errorhandler [$ namespace current] $status $cres $copts]$ }$ }$ lindex $cres$ }$ ]] [uplevel {namespace current}]]]$ }$ ====== Here is a variant that improves runtime performance quite a bit by rewriting each command of the body when the procedure is created. This leaves no private space for `[catch]` to create its output variables in, so it stuffs them into `$::tcl::cres` and `::tcl::copts` instead instead: ====== ::tcl::proc proc {name args body} {$ set newbody {}$ ::foreach command [nocomments [scriptSplit $body]] {$ ::append newbody [string map [list {${command}} [list $command]] {$ set ::tcl::ccode [$ ::catch {if 1 {{*}[::cmdhandler [namespace current] \$ ${command}]}} ::tcl::cres ::tcl::copts]$ ::if {$::tcl::ccode} {$ if 1 [$ ::errorhandler [namespace current] \$ $::tcl::ccode $::tcl::cres $::tcl::copts]$ } else {$ ::lindex $::tcl::cres$ }$ }]$ }$ ::uplevel [::list ::tcl::proc $name $args $newbody]$ }$ ====== Here are some example handlers that don't do much of anything: $ ====== ::tcl::proc cmdhandler {namespace command} {$ #::puts stderr [::list {now executing} $command]$ return $command$ }$ $ ::tcl::proc errorhandler {namespace code cres copts} {$ if {$code == 2} {$ tailcall return -code $code $cres$ }$ ::puts stderr [list {got an error} $code xxx $cres yyy $copts]$ tailcall return -code $code $cres$ }$ ====== <> debugging | macro