Skip to content

Commit e3c2247

Browse files
committed
FEAT: implemented catch/all which may be used to catch all throws (named and unnamed)
resolves: Oldes/Rebol-issues#1518 resolves: Oldes/Rebol-issues#1520
1 parent 7e25856 commit e3c2247

File tree

3 files changed

+35
-11
lines changed

3 files changed

+35
-11
lines changed

src/boot/natives.reb

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ catch: native [
7575
block [block!] {Block to evaluate}
7676
/name {Catches a named throw}
7777
word [word! block!] {One or more names}
78+
/all {Catches all throws, named and unnamed}
7879
/quit {Special catch for QUIT native}
7980
/recover code [block!] "Code to be evaluated on a catch"
8081
]

src/core/n-control.c

+20-11
Original file line numberDiff line numberDiff line change
@@ -413,11 +413,11 @@ enum {
413413
REBVAL *val;
414414
REBVAL *ret;
415415
REBCNT sym;
416-
REBVAL recover = *D_ARG(ARG_CATCH_RECOVER);
416+
REBVAL recover = *D_ARG(ARG_CATCH_CODE);
417417
REBVAL *last_result = Get_System(SYS_STATE, STATE_LAST_RESULT);
418418
REBOOL quit;
419419

420-
if (D_REF(ARG_CATCH_QUIT)) { //QUIT
420+
if (D_REF(ARG_CATCH_QUIT)) {
421421
quit = Try_Block_Halt(VAL_SERIES(D_ARG(ARG_CATCH_BLOCK)), VAL_INDEX(D_ARG(ARG_CATCH_BLOCK)));
422422
ret = DS_NEXT;
423423
if (quit) {
@@ -445,32 +445,41 @@ enum {
445445

446446
// If it is a throw, process it:
447447
if (IS_ERROR(ret) && VAL_ERR_NUM(ret) == RE_THROW) {
448+
// Get optional thrown name
449+
sym = VAL_ERR_SYM(ret);
448450

449-
// If a named throw, then check it:
450-
if (D_REF(ARG_CATCH_NAME)) { // /name
451+
if (D_REF(ARG_CATCH_ALL)) goto caught;
451452

452-
sym = VAL_ERR_SYM(ret);
453-
val = D_ARG(ARG_CATCH_WORD); // name symbol
453+
// If a named catch, then check it:
454+
if (D_REF(ARG_CATCH_NAME)) {
455+
val = D_ARG(ARG_CATCH_WORD); // catch/name value
454456

455457
// If name is the same word:
456-
if (IS_WORD(val) && sym == VAL_WORD_CANON(val)) goto got_err;
458+
if (IS_WORD(val) && sym == VAL_WORD_CANON(val)) goto caught;
457459

458460
// If it is a block of words:
459461
else if (IS_BLOCK(val)) {
460462
for (val = VAL_BLK_DATA(val); NOT_END(val); val++) {
461-
if (IS_WORD(val) && sym == VAL_WORD_CANON(val)) goto got_err;
463+
if (IS_WORD(val) && sym == VAL_WORD_CANON(val)) goto caught;
462464
}
463465
}
466+
//else if (IS_LOGIC(val) && VAL_LOGIC(val)) goto caught; // used CATCH/name [] true
464467
} else {
465-
got_err:
468+
// Used catch without name. If there was thrown a name, then let it pass thru.
469+
if (sym != 0) {
470+
*DS_RETURN = *ret;
471+
return R_RET;
472+
}
473+
caught: // Thrown is being caught.
474+
// Store thrown value as the last result.
466475
*ds = *(VAL_ERR_VALUE(ret));
467476
*last_result = *ds;
477+
// If there is a recovery code, then evaluate it.
468478
if (IS_BLOCK(&recover)) {
469479
DS_NEXT;
470480
DO_BLK(&recover);
471481
DS_POP;
472-
}
473-
482+
}
474483
return R_RET;
475484
}
476485
}

src/tests/units/evaluation-test.r3

+14
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,20 @@ Rebol [
784784
a = 1
785785
]
786786

787+
--test-- "nested catch"
788+
;@@ https://github.com/Oldes/Rebol-issues/issues/1518
789+
--assert 1 = catch/name [a: 0 catch [++ a throw/name 1 'foo] a: a * 10] 'foo
790+
--assert 1 = a
791+
--assert 1 = catch/name [a: 0 catch/name [++ a throw/name 1 'foo] 'bar a: a * 10] 'foo
792+
--assert 1 = a
793+
--test-- "catch/all"
794+
;@@ https://github.com/Oldes/Rebol-issues/issues/1520
795+
--assert 1 = catch/all [a: 0 throw/name 1 'foo a: a * 10]
796+
--assert 0 = a
797+
--assert 1 = catch/all [a: 0 catch [++ a throw/name 1 'foo] a: a * 10]
798+
--assert 1 = a
799+
--assert 1 = catch/all [a: 0 catch/name [++ a throw/name 1 'foo] 'bar a: a * 10]
800+
--assert 1 = a
787801

788802
===end-group===
789803

0 commit comments

Comments
 (0)