Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
88 views
in Technique[技术] by (71.8m points)

guile - How to show error message from eval in Scheme?

I'm trying to create code that evaluates expression and return error as string for error:

(cond-expand
  (gambit)
  (gauche)
  (kawa)
  (guile
   (import (rnrs base)
           (rnrs exceptions)
           (rnrs conditions))
   (define (error-object-message cond)
     (condition-message cond))))

(define (evaluate expr env)
  (call-with-current-continuation
   (lambda (exit)
     (with-exception-handler
      (lambda (e)
        (exit (error-object-message e)))
      (lambda ()
        (eval expr env))))))

;; trigger error
(display (evaluate 'xxx (interaction-environment)))
(newline)

I've got

  • Guile message Unbound variable: ~S how to get actual error message and not a template?
  • Kawa exception: Argument #1 'unbound location: xxx' to 'error-object-message' has wrong type (gnu.mapping.UnboundLocationException) (gnu.mapping.UnboundLocationException cannot be cast to kawa.lang.NamedException)
  • Gauche core dump
  • Gambit freezes

NOTE: this is part of REPL that I'm testing in all Scheme implementations that I have on my system. It almost work, it can run itself, but I would like to show proper error message when exception happen, instead of exiting the REPL.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The reason you get an infinite loop with Gambit is that the variable xxx is unbound so the exception handler (lambda (e) (exit (error-object-message e))) is called with an unbound-global-exception object and this causes error-object-message to be called but the parameter is not an error-object (which is specific to the exceptions raised by a call to the error procedure) so this raises a type-exception object that causes the same exception handler to be called, and so on forever.

If you want an exception handling that "pops" the current exception handler, use with-exception-catcher instead of with-exception-handler. This will avoid the infinite loop.

Converting an exception object to a string can be done in Gambit this way:

(define (exception->string exc)
  (with-output-to-string
    (lambda ()
      (display-exception exc))))

It works for error-objects and other kinds of exceptions, and also any non-exception object.

This is a more portable solution (superficially tested):

(import (scheme base)
        (scheme r5rs))

(cond-expand
  ((or lips kawa gauche)
   (define (exception->string exc)
     (error-object-message exc)))
  (gambit
   (define (exception->string exc)
     (with-output-to-string
       (lambda ()
         (display-exception exc)))))

  (guile
   (import (rnrs base)
           (rnrs exceptions)
           (rnrs conditions))
   (define (exception->string exc)
     (condition-message exc))))

(define (evaluate expr env)
  (call-with-current-continuation
   (lambda (exit)
     (with-exception-handler
      (lambda (e)
        (exit (exception->string e)))
      (lambda ()
        (eval expr env))))))

(display (evaluate 'xxx (interaction-environment)))
(newline)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...