diff --git a/doc/es.1 b/doc/es.1 index 3fb8e790..1dd8b0f9 100644 --- a/doc/es.1 +++ b/doc/es.1 @@ -1959,12 +1959,18 @@ Exits the current loop. .I Value is used as the return value for the loop command. .TP -.Cr "catch \fIcatcher body\fP" +.Cr "catch \fR[\fP\fIexception\fP\fR]\fP \fIcatcher body\fP" Runs .IR body . -If it raises an exception, +If it raises an exception, and +.IR exception +is either not provided or matches the first term of the exception, .IR catcher is run and passed the exception as an argument. +If +.IR exception +is provided, then the passed argument does not include the first term +of the exception, which has already been matched. .TP .Cr "cd \fR[\fP\fIdirectory\fP\fR]\fP" Changes the current directory to diff --git a/initial.es b/initial.es index 987919a0..b24b5357 100644 --- a/initial.es +++ b/initial.es @@ -65,8 +65,6 @@ fn-. = $&dot fn-access = $&access -fn-break = $&break -fn-catch = $&catch fn-echo = $&echo fn-exec = $&exec fn-forever = $&forever @@ -102,6 +100,30 @@ fn-break = throw break fn-exit = throw exit fn-return = throw return +# The catch function wraps $&catch and adds handling for "selectable +# exceptions": if catch is called like `catch foo $catcher $body`, then +# `catch` will only actually catch the 'foo' exception, and no others. + +fn-catch = $&noreturn @ catcher body { + let (exception = ()) { + if {!~ $#body (0 1)} { + (exception catcher body) = $catcher $body + } + if {!~ $#body (0 1)} { + throw error catch 'usage: catch [exception] catcher body' + } + $&catch @ e rest { + if {~ $#exception 0} { + $&noreturn $catcher $e $rest + } {~ $exception $e} { + $&noreturn $catcher $rest + } { + throw $e $rest + } + } $body + } +} + # unwind-protect is a simple wrapper around catch that is used # to ensure that some cleanup code is run after running a code # fragment. This function must be written with care to make diff --git a/prim-ctl.c b/prim-ctl.c index d8d4e31c..7201e3f5 100644 --- a/prim-ctl.c +++ b/prim-ctl.c @@ -86,6 +86,7 @@ PRIM(catch) { SIGCHK(); } while (retry); + SIGCHK(); RefEnd(lp); RefReturn(result); } diff --git a/share/path-cache.es b/share/path-cache.es index d9c8137b..17872a3d 100644 --- a/share/path-cache.es +++ b/share/path-cache.es @@ -58,12 +58,8 @@ fn recache progs { fn precache progs { let (result = ()) for (p = $progs) { - catch @ e type msg { - if {~ $e error} { - echo >[1=2] $msg - } { - throw $e $type $msg - } + catch error @ _ msg { + echo >[1=2] $msg } { result = $result <={%pathsearch $p} } diff --git a/share/status.es b/share/status.es index faf5ae3b..24ff5737 100644 --- a/share/status.es +++ b/share/status.es @@ -20,11 +20,9 @@ fn %interactive-loop { noexport = $noexport status status = <=true fn-%dispatch = $&noreturn @ { - catch @ e rest { - if {~ $e return} { - status = $rest - } - throw $e $rest + catch return @ value { + status = $value + return $value } { status = <={$d $*} }