On this page:
«error-handling»

6 Exceptions

There are as many error handling strategies as programming languages, ranging from “drop everything and quit” to “don’t have errors.” Here’s a simple one: if an error occurs, put it on the stack and call the function current-error-handler. If that’s not defined, the interpreter has no choice but to quit altogether.

Overriding current-error-handler and invoking it in the right place (as soon as the error happens, before touching the stack) should give it as much information as it needs to do whatever error handling is necessary.

All the pieces are already in place: interp-call, defined in Core operations, is already set up to use interp-try-eval.

; Custom error type that can be put on the stack in its component parts
(struct builtin-failure exn:fail
  ([name : Symbol] [irritants : (Listof Any)])
  #:transparent
  #:type-name Builtin-Failure)
 
; Utility for builtins to signal an error
(: interp-error (All (A) ((Symbol) #:rest Any . ->* . A)))
(define (interp-error name . irritants)
  (raise (builtin-failure
           "Builtin failure"
           (current-continuation-marks)
           name irritants)))
 
(: interp-handle-error (Context Stack Symbol (Listof Any)
                                . -> . (Values Context Stack)))
(define (interp-handle-error ctx stack name irritants)
  (if (context-resolve ctx 'current-error-handler)
    ; Put the error on the stack
    (interp-call ctx
                 (list* name irritants stack)
                 'current-error-handler)
    ; Kill the interpreter if current-error-handler isn't defined
    (error "Unhandled error" name irritants stack)))
 
(: interp-try-eval (Context Stack Symbol Function
                            . -> . (Values Context Stack)))
(define (interp-try-eval ctx stack name f)
  (with-handlers
    ; Builtin failures get the arguments given to interp-error
    ([builtin-failure?
       (lambda ([e : Builtin-Failure])
         (interp-handle-error ctx stack
                              (builtin-failure-name e)
                              (cons name (builtin-failure-irritants e))))]
     [exn:fail? ; should this catch all exceptions, including breaks?
       (lambda ([e : exn])
         ; Try to deal with this error in a reasonable way
         (interp-handle-error ctx stack
                              name
                              (list (exn-message e))))])
    (interp-eval ctx stack f)))
 
; TODO tests for this.