/* catch.h
 *
 * C-interface to catch, throw and unwind-protect like facilities.
 *
 * Copyright Niels Möller <nisse@lysator.liu.se> 1995
 *
 * Freely distributable under the terms and conditions of the
 * GNU General Public License.
 */

#include <frame_stack.h>

extern struct frame_stack the_frame_stack;

#define catch_tag frame_id
#define protect_tag frame_id


void /* Initialize stack */
catch_init(void);

/* Usage:
 *
 * catch_tag tag;
 * int result = CATCH(&tag, {
 *                            body
 *                          });
 *
 * result is either the value of the last expression in body or, if
 * the body was terminated by a THROW(), the value passed to THROW().
 */

#define CATCH(tag_pointer, body) \
({ \
    int __CATCH_result; \
    *(tag_pointer) = fr_catch_setup(&the_frame_stack), \
    __CATCH_result = (setjmp(( (struct frstack_catch_frame *) \
			       *(tag_pointer) )->where) \
		      ? : (body)); \
    frstack_free(&the_frame_stack, *(tag_pointer)); \
    __CATCH_result; \
})


/* Usage:
 *
 * catch_tag tag;
 * int value;
 * (void) THROW(tag, value);
 *
 * Passes control to the CATCH that created tag. Never returns.
 */

#define THROW(tag, value) \
fr_throw(&the_frame_stack, tag, value)


/* Usage:
 *
 * PROTECT( {
 *            body
 *          },
 *    {
 *      cleanup
 *    });
 *
 * body is executed. When finished, or if a THROW() terminates
 * the execution, the cleanup is executed.
 */

#define PROTECT(body, cleanup) \
{ \
    void __fr_PROTECT_fn(void) cleanup \
    protect_tag __fr_PROTECT_tag = \
	  fr_protect_fn0(&the_frame_stack, &__fr_PROTECT_fn); \
    body \
    frstack_free(&the_frame_stack, __fr_PROTECT_tag); \
    __fr_PROTECT_fn(); \
}				   
