Tcl & Tk/팁 (Tip)

try/catch/finally 커맨드

티클러 2025. 3. 26. 10:35

출처: http://people.man.ac.uk/~zzcgudf/tcl/try.tcl

 

아래의 코드로 Tcl에서도 try/catch/finally 구문을 사용할 수 있습니다. 이 스크립트를 사용하면 예외 처리를 쉽게 할 수 있어 스크립트의 오류를 최소한의 코드로 구조화된 방식으로 처리할 수 있습니다. Tcl 8.0 이상에서 사용 가능합니다.

namespace eval ::try {
    namespace export try
    variable bodyMatch {    \("uplevel" body line}
    proc helper {script part {eiv ei} {ecv ec} {codev code} {msgv msg}} {
        global errorInfo errorCode
        variable bodyMatch
        upvar 1 $eiv ei $ecv ec $codev code $msgv msg
        set code [catch [list uplevel 2 $script] msg]
        set ec $errorCode
        set lines [split $errorInfo "\n"]
        if {$code == 1} {
            while {![regexp $bodyMatch [lindex $lines end]]} {
                set lines [lrange $lines 0 [expr {[llength $lines]-2}]]
            }
            regsub {"uplevel" body} [lindex $lines end] $part fixed
            set lines [lrange $lines 0 [expr {[llength $lines]-2}]]
            lappend lines $fixed
        }
        set ei [join $lines "\n"]
    }
    proc try {body args} {
        # First, parse apart the args
        set hasFinally 0
        set catches {}
        for {set i 0} {$i<[llength $args]} {incr i} {
            set word [lindex $args $i]
            if {![string compare $word catch]} {
                if {$i+1 >= [llength $args]} {
                    return -code error "missing matcher to catch"
                } elseif {$i+2 >= [llength $args]} {
                    return -code error "missing body to catch"
                }
                lappend catches [lindex $args [incr i]]
                lappend catches [lindex $args [incr i]]
            } elseif {![string compare $word finally]} {
                if {$i+1 >= [llength $args]} {
                    return -code error "missing body to finally"
                }
                set finally [lindex $args [incr i]]
                set hasFinally 1
            } else {
                return -code error "unknown keyword \"$word\" to try:\
                        should be \"try body ?catch matcher body ...?\
                        ?finally body?\""
            }
        }

        # Now evaluate the body
        helper $body "try body"

        # Handle errors
        if {$code == 1} {
            foreach {matcher handler} $catches {
                if {[string match $matcher $ec]} {
                    helper $handler "catch \"$matcher\" body"
                    break
                }
            }
        }

        # Do the finally clause
        if {$hasFinally} {
            helper $finally "finally clause" a b c d
            if {$c} {
                set ei $a
                set ec $b
                set code $c
                set msg $d
            }
        }

        # Now we can return.  Phew!
        return -code $code -errorinfo $ei -errorcode $ec $msg
    }
}
namespace import ::try::try

## EXAMPLE ##
# try {
#     set f [open /non/existant/file]
# } catch {POSIX ENOENT *} {
#     puts "That file doesn't exist!"
# } catch {POSIX EACCES *} {
#     puts "You may not open that file!"
# } finally {
#     puts "Wibble..."
# }

try.tcl
0.00MB