Skip to content

Commit b917152

Browse files
committed
FEAT: new /recover option of the catch function
resolves: Oldes/Rebol-issues#1521
1 parent d624e65 commit b917152

File tree

3 files changed

+51
-4
lines changed

3 files changed

+51
-4
lines changed

src/boot/natives.reb

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ catch: native [
7676
/name {Catches a named throw}
7777
word [word! block!] {One or more names}
7878
/quit {Special catch for QUIT native}
79+
/recover code [block!] "Code to be evaluated on a catch"
7980
]
8081

8182
;cause: native [

src/core/n-control.c

+16-2
Original file line numberDiff line numberDiff line change
@@ -413,10 +413,12 @@ enum {
413413
REBVAL *val;
414414
REBVAL *ret;
415415
REBCNT sym;
416+
REBVAL recover = *D_ARG(6);
417+
REBVAL *last_result = Get_System(SYS_STATE, STATE_LAST_RESULT);
416418

417419
if (D_REF(4)) { //QUIT
418420
if (Try_Block_Halt(VAL_SERIES(D_ARG(1)), VAL_INDEX(D_ARG(1)))) {
419-
// We are here because of a QUIT/HALT condition.
421+
// We are here because of a QUIT or HALT condition.
420422
ret = DS_NEXT;
421423
if (VAL_ERR_NUM(ret) == RE_QUIT)
422424
ret = VAL_ERR_VALUE(ret);
@@ -425,6 +427,11 @@ enum {
425427
//Halt_Code(RE_HALT, 0); // Don't use this if we want to be able catch all!
426428
else
427429
Crash(RP_NO_CATCH);
430+
431+
if (IS_BLOCK(&recover)) {
432+
DO_BLK(&recover);
433+
}
434+
428435
*DS_RETURN = *ret;
429436
return R_RET;
430437
}
@@ -455,10 +462,17 @@ enum {
455462
} else {
456463
got_err:
457464
*ds = *(VAL_ERR_VALUE(ret));
465+
*last_result = *ds;
466+
if (IS_BLOCK(&recover)) {
467+
DS_NEXT;
468+
DO_BLK(&recover);
469+
DS_POP;
470+
}
471+
458472
return R_RET;
459473
}
460474
}
461-
475+
// No throw, or a throw with unhandled name... return just result of the block evaluation
462476
return R_TOS1;
463477
}
464478

src/tests/units/evaluation-test.r3

+34-2
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,10 @@ Rebol [
731731

732732

733733
===start-group=== "CATCH"
734+
;@@ https://github.com/Oldes/Rebol-issues/issues/1518
735+
;@@ https://github.com/Oldes/Rebol-issues/issues/1520
736+
;@@ https://github.com/Oldes/Rebol-issues/issues/1734
737+
;@@ https://github.com/Oldes/Rebol-issues/issues/1742
734738
--test-- "catch/quit [halt]"
735739
;@@ https://github.com/Oldes/Rebol-issues/issues/1742
736740
a: 0 catch/quit [++ a halt ++ a]
@@ -740,11 +744,39 @@ Rebol [
740744
;@@ https://github.com/Oldes/Rebol-issues/issues/1734
741745
a: 0
742746
--assert unset? catch/quit [++ a quit ++ a]
743-
--assert a == 1;
747+
--assert a == 1
744748
--assert 100 = catch/quit [++ a quit/return 100 ++ a]
745-
--assert a == 2;
749+
--assert a == 2
746750
--assert 0 = call/shell/wait join system/options/boot { --do "quit"}
747751
--assert 100 = call/shell/wait join system/options/boot { --do "quit/return 100"}
752+
--test-- "nested catch"
753+
a: 0
754+
--assert 'x = catch [++ a catch/quit [++ a quit a: 0] a: a * 2 throw 'x a: a * 100]
755+
--assert a == 4
756+
a: 0
757+
--assert 'x = catch [++ a catch/quit [++ a throw 'x a: 0] a: a * 2 quit 'x a: a * 100]
758+
--assert a == 2
759+
a: 0
760+
--assert unset? catch/quit [++ a a: a + catch [++ a throw 100 a: 0] a: a * 2 quit a: a * 100]
761+
--assert a == 202
762+
a: 0
763+
--assert unset? catch/quit [++ a a: a + catch [++ a quit a: 0] a: a * 2 throw 100 a: a * 100]
764+
--assert a == 2
765+
766+
--test-- "catch/recover"
767+
;@@ https://github.com/Oldes/Rebol-issues/issues/1521
768+
--assert unset? catch/quit/recover [a: 1 quit a: 2][a: a * 10]
769+
--assert a = 10
770+
771+
--assert 2 = catch/quit/recover [a: 2][a: a * 10]
772+
--assert a = 2
773+
774+
--assert 'x = catch/recover [a: 1 throw 'x a: 2][a: a * 10]
775+
--assert a = 10
776+
777+
--assert 3 = catch/recover [a: 1 throw 3 a: 2][a: system/state/last-result a: a * 10]
778+
--assert a = 30
779+
748780

749781
===end-group===
750782

0 commit comments

Comments
 (0)