mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-10-27 04:40:59 +01:00
20812: Add functions for exception handling
This commit is contained in:
parent
4040e0bb1f
commit
20018230ee
5 changed files with 166 additions and 3 deletions
|
|
@ -1,3 +1,9 @@
|
||||||
|
2005-02-15 Peter Stephenson <pws@csr.com>
|
||||||
|
|
||||||
|
* 20812: Doc/Zsh/contrib.yo, Functions/Exceptions/catch,
|
||||||
|
Functions/Exceptions/throw, Src/zsh.mdd: add functions for
|
||||||
|
exception handling using "always" block.
|
||||||
|
|
||||||
2005-02-14 Peter Stephenson <pws@csr.com>
|
2005-02-14 Peter Stephenson <pws@csr.com>
|
||||||
|
|
||||||
* 20811: configure.ac: Copy the trick for finding the
|
* 20811: configure.ac: Copy the trick for finding the
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ startmenu()
|
||||||
menu(Utilities)
|
menu(Utilities)
|
||||||
menu(Prompt Themes)
|
menu(Prompt Themes)
|
||||||
menu(ZLE Functions)
|
menu(ZLE Functions)
|
||||||
|
menu(Exception Handling)
|
||||||
menu(MIME Functions)
|
menu(MIME Functions)
|
||||||
menu(Other Functions)
|
menu(Other Functions)
|
||||||
endmenu()
|
endmenu()
|
||||||
|
|
@ -345,7 +346,7 @@ normally call a theme's setup function directly.
|
||||||
)
|
)
|
||||||
enditem()
|
enditem()
|
||||||
|
|
||||||
texinode(ZLE Functions)(MIME Functions)(Prompt Themes)(User Contributions)
|
texinode(ZLE Functions)(Exception Handling)(Prompt Themes)(User Contributions)
|
||||||
sect(ZLE Functions)
|
sect(ZLE Functions)
|
||||||
|
|
||||||
subsect(Widgets)
|
subsect(Widgets)
|
||||||
|
|
@ -1033,7 +1034,93 @@ whether the tt(widget) style is used.
|
||||||
)
|
)
|
||||||
enditem()
|
enditem()
|
||||||
|
|
||||||
texinode(MIME Functions)(Other Functions)(ZLE Functions)(User Contributions)
|
texinode(Exception Handling)(MIME Functions)(ZLE Functions)(User Contributions)
|
||||||
|
sect(Exception Handling)
|
||||||
|
|
||||||
|
Two functions are provided to enable zsh to provide exception handling in a
|
||||||
|
form that should be familiar from other languages.
|
||||||
|
|
||||||
|
startitem()
|
||||||
|
findex(throw)
|
||||||
|
item(tt(throw) var(exception))(
|
||||||
|
The function tt(throw) throws the named var(exception). The name is
|
||||||
|
an arbitrary string and is only used by the tt(throw) and tt(catch)
|
||||||
|
functions. An exception is for the most part treated the same as a
|
||||||
|
shell error, i.e. an unhandled exception will cause the shell to abort all
|
||||||
|
processing in a function or script and to return to the top level in an
|
||||||
|
interative shell.
|
||||||
|
)
|
||||||
|
item(tt(catch) var(exception-pattern))(
|
||||||
|
The function tt(catch) returns status zero if an exception was thrown and
|
||||||
|
the pattern var(exception-pattern) matches its name. Otherwise it
|
||||||
|
returns status 1. var(exception-pattern) is a standard
|
||||||
|
shell pattern, respecting the current setting of the tt(EXTENDED_GLOB)
|
||||||
|
option. An alias tt(catch) is also defined to prevent the argument to the
|
||||||
|
function from matching filenames, so patterns may be used unquoted. Note
|
||||||
|
that as exceptions are not fundamentally different from other shell errors
|
||||||
|
it is possible to catch shell errors by using an empty string as the
|
||||||
|
exception name. The shell variable tt(CAUGHT) is set by tt(catch) to the
|
||||||
|
name of the exception caught. It is possible to rethrow an exception by
|
||||||
|
calling the tt(throw) function again once an exception has been caught.
|
||||||
|
findex(catch)
|
||||||
|
)
|
||||||
|
enditem()
|
||||||
|
|
||||||
|
The functions are designed to be used together with the tt(always) construct
|
||||||
|
described in
|
||||||
|
ifzman(zmanref(zshmisc))\
|
||||||
|
ifnzman(noderef(Complex Commands)). This is important as only this
|
||||||
|
construct provides the required support for exceptions. A typical example
|
||||||
|
is as follows.
|
||||||
|
|
||||||
|
example({
|
||||||
|
# "try" block
|
||||||
|
# ... nested code here calls "throw MyExcept"
|
||||||
|
} always {
|
||||||
|
# "always" block
|
||||||
|
if catch MyExcept; then
|
||||||
|
print "Caught exception MyExcept"
|
||||||
|
elif catch ''; then
|
||||||
|
print "Caught a shell error. Propagating..."
|
||||||
|
throw ''
|
||||||
|
fi
|
||||||
|
# Other exceptions are not handled but may be caught further
|
||||||
|
# up the call stack.
|
||||||
|
})
|
||||||
|
|
||||||
|
If all exceptions should be caught, the following idiom might be
|
||||||
|
preferable.
|
||||||
|
|
||||||
|
example({
|
||||||
|
# ... nested code here throws an exception
|
||||||
|
} always {
|
||||||
|
if catch *; then
|
||||||
|
case $CAUGHT in
|
||||||
|
LPAR()MyExcept+RPAR()
|
||||||
|
print "Caught my own exception"
|
||||||
|
;;
|
||||||
|
LPAR()*RPAR()
|
||||||
|
print "Caught some other exception"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
})
|
||||||
|
|
||||||
|
In common with exception handling in other languages, the exception may be
|
||||||
|
thrown by code deeply nested inside the `try' block. However, note that it
|
||||||
|
must be thrown inside the current shell, not in a subshell forked for a
|
||||||
|
pipline, parenthesised current-shell construct, or some form of
|
||||||
|
substitution.
|
||||||
|
|
||||||
|
The system internally uses the shell variable tt(EXCEPTION) to record the
|
||||||
|
name of the exception between throwing and catching. One drawback of this
|
||||||
|
scheme is that if the exception is not handled the variable tt(EXCEPTION)
|
||||||
|
remains set and may be incorrectly recognised as the name of an exception
|
||||||
|
if a shell error subsequently occurs. Adding tt(unset EXCEPTION) at the
|
||||||
|
start of the outermost layer of any code that uses exception handling will
|
||||||
|
eliminate this problem.
|
||||||
|
|
||||||
|
texinode(MIME Functions)(Other Functions)(Exception Handling)(User Contributions)
|
||||||
sect(MIME Functions)
|
sect(MIME Functions)
|
||||||
|
|
||||||
Three functions are available to provide handling of files recognised by
|
Three functions are available to provide handling of files recognised by
|
||||||
|
|
|
||||||
41
Functions/Exceptions/catch
Normal file
41
Functions/Exceptions/catch
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Catch an exception. Returns 0 if the exception in question was caught.
|
||||||
|
# The first argument gives the exception to catch, which may be a
|
||||||
|
# pattern.
|
||||||
|
# This must be within an always-block. A typical set of handlers looks
|
||||||
|
# like:
|
||||||
|
# {
|
||||||
|
# # try block; something here throws exceptions
|
||||||
|
# } always {
|
||||||
|
# if catch MyExcept; then
|
||||||
|
# # Handler code goes here.
|
||||||
|
# print Handling exception MyExcept
|
||||||
|
# elif catch *; then
|
||||||
|
# # This is the way to implement a catch-all.
|
||||||
|
# print Handling any other exception
|
||||||
|
# fi
|
||||||
|
# }
|
||||||
|
# As with other languages, exceptions do not need to be handled
|
||||||
|
# within an always block and may propagate to a handler further up the
|
||||||
|
# call chain.
|
||||||
|
#
|
||||||
|
# It is possible to throw an exception from within the handler by
|
||||||
|
# using "throw".
|
||||||
|
#
|
||||||
|
# The shell variable $CAUGHT is set to the last exception caught,
|
||||||
|
# which is useful if the argument to "catch" was a pattern.
|
||||||
|
#
|
||||||
|
# Use "function" keyword in case catch is already an alias.
|
||||||
|
function catch {
|
||||||
|
if [[ $TRY_BLOCK_ERROR -gt 0 && $EXCEPTION = ${~1} ]]; then
|
||||||
|
(( TRY_BLOCK_ERROR = 0 ))
|
||||||
|
CAUGHT="$EXCEPTION"
|
||||||
|
unset EXCEPTION
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
# Never use globbing with "catch".
|
||||||
|
alias catch="noglob catch"
|
||||||
|
|
||||||
|
catch "$@"
|
||||||
29
Functions/Exceptions/throw
Normal file
29
Functions/Exceptions/throw
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Throw an exception.
|
||||||
|
# The first argument is a string giving the exception. Other arguments
|
||||||
|
# are ignored.
|
||||||
|
#
|
||||||
|
# This is designed to be called somewhere inside a "try-block", i.e.
|
||||||
|
# some code of the form:
|
||||||
|
# {
|
||||||
|
# # try-block
|
||||||
|
# } always {
|
||||||
|
# # always-block
|
||||||
|
# }
|
||||||
|
# although as normal with exceptions it might be hidden deep inside
|
||||||
|
# other code. Note, however, that it must be code running within the
|
||||||
|
# current shell; with shells, unlike other languages, it is quite easy
|
||||||
|
# to miss points at which the shell forks.
|
||||||
|
#
|
||||||
|
# If there is nothing to catch an exception, this behaves like any
|
||||||
|
# other shell error, aborting to the command prompt or abandoning a
|
||||||
|
# script.
|
||||||
|
|
||||||
|
# The following must not be local.
|
||||||
|
EXCEPTION="$1"
|
||||||
|
if (( TRY_BLOCK_ERROR == 0 )); then
|
||||||
|
# We are throwing an exception from the middle of an always-block.
|
||||||
|
# We can do this by restoring the error status from the try-block.
|
||||||
|
(( TRY_BLOCK_ERROR = 1 ))
|
||||||
|
fi
|
||||||
|
# Raise an error, but don't show an error message.
|
||||||
|
{ ${:?THROW} } 2>/dev/null
|
||||||
|
|
@ -2,7 +2,7 @@ name=zsh/main
|
||||||
link=static
|
link=static
|
||||||
load=yes
|
load=yes
|
||||||
# load=static should replace use of alwayslink
|
# load=static should replace use of alwayslink
|
||||||
functions='Functions/Misc/* Functions/MIME/* Functions/Prompts/*'
|
functions='Functions/Exceptions/* Functions/Misc/* Functions/MIME/* Functions/Prompts/*'
|
||||||
|
|
||||||
nozshdep=1
|
nozshdep=1
|
||||||
alwayslink=1
|
alwayslink=1
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue