diff --git a/doc/es.1 b/doc/es.1 index e87d5e1c..b9eacc6b 100644 --- a/doc/es.1 +++ b/doc/es.1 @@ -1973,12 +1973,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. Signals are blocked during the execution of .IR catcher and signal exceptions will only be raised after it has finished running. diff --git a/initial.es b/initial.es index b8e422b3..7e8ba136 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 @@ -75,6 +73,7 @@ fn-if = $&if fn-newpgrp = $&newpgrp fn-result = $&result fn-throw = $&throw +fn-catch = $&catch fn-umask = $&umask fn-wait = $&wait @@ -170,10 +169,7 @@ fn var { for (i = <={%var $*}) echo $i } fn whatis { let (result = ) { for (i = $*) { - catch @ e from message { - if {!~ $e error} { - throw $e $from $message - } + catch error @ from message { echo >[1=2] $message result = $result 1 } { @@ -190,10 +186,7 @@ fn whatis { # does not catch the return exception. It does, however, catch break. fn-while = $&noreturn @ cond body { - catch @ e value { - if {!~ $e break} { - throw $e $value - } + catch break @ value { result $value } { let (result = <=true) diff --git a/prim-ctl.c b/prim-ctl.c index 1b0a86c6..b8a34173 100644 --- a/prim-ctl.c +++ b/prim-ctl.c @@ -47,12 +47,18 @@ PRIM(throw) { PRIM(catch) { Atomic retry; + int argc = length(list); - if (list == NULL) - fail("$&catch", "usage: catch catcher body"); + if (argc != 2 && argc != 3) + fail("$&catch", "usage: catch [exception] catcher body"); Ref(List *, result, NULL); Ref(List *, lp, list); + Ref(char *, exc, NULL); + if (argc == 3) { + exc = getstr(lp->term); + lp = lp->next; + } do { List *e = NULL; @@ -62,7 +68,14 @@ PRIM(catch) { result = eval(lp->next, NULL, evalflags); - CatchException (frombody) + CatchException (volatile frombody) + + if (exc != NULL) { + if (termeq(frombody->term, exc)) + frombody = frombody->next; + else + throw(frombody); + } blocksignals(); ExceptionHandler @@ -89,7 +102,7 @@ PRIM(catch) { throw(e); } while (retry); - RefEnd(lp); + RefEnd2(exc, 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 $*} }