On 24-Apr-09, at 6:49 AM, Valeriya Pudova wrote:
Hello good people,
I found that sometime gsi (or gsc) does not report the error location refering information. It make hard job to find location of error.
After few tests I found simple code which display this issue.
(eval '(define (foo) (display (/ 1 0)))) (foo)
*** ERROR IN foo -- Divide by zero, (/ 1 0)
Not (eval) makes the problem, because this variant works
(eval '(define (foo) (/ 1 0))) (foo)
*** ERROR IN "test2.scm"@1.33 -- Divide by zero (/ 1 0)
And not (display):
(define (foo) (display (/ 1 0))) (foo)
*** ERROR IN foo, "test2.scm"@1.25 -- Divide by zero (/ 1 0)
Could anybody explain this?
The source code location is attached to "source" objects. These source objects are returned by the reader that is called by the "load" procedure and the REPL. The "eval" procedure can accept as its parameter expressions that are represented as source objects or pure S- expressions, i.e. (nested) Scheme lists, symbols, numbers, etc. When eval creates a continuation for a non-tail procedure call, it leaves in the continuation a reference to the expression that corresponds to the call (note that in the case of tail procedure calls no continuation is created so this information is not saved). When an error is encountered, such as (/ 1 0), the continuation of the primitive (here: /) which detected the error is captured and passed to the debugger which starts a nested REPL. The debugger uses this continuation to recover the location information for the error message. So the location of the call to / will not be recovered when eval was passed a pure S-expression (as in your first test above) because the expression saved in the continuation has no source code location information attached to it. In the case of your second test, you get the location of the call to foo, because foo has tail- called /, so the continuation of / is the continuation created for the call to foo (and the call to foo is not inside the S-expression passed to eval, i.e. it is a source code object with location information).
The following macro definition might prove useful for debugging:
(##define-syntax attach-this-locat (lambda (src) (let ((expr (cadr (##source-code src))) (locat (##source-locat src))) `(##make-source ,expr ',locat))))
The call
(eval (attach-this-locat '(+ 1 (/ 1 0))))
will give a divide-by-zero error with the location of the call to attach-this-locat. This is not perfect, but it at least gives you some location information. It works by extracting the source code location from the parameter (i.e. src) and attaching that location to the S-expression that is then passed to eval (to turn it into a source object).
You may also want to use (declare (not proper-tail-calls)) at the top of your code. It requests that the interpreter and compiler treat tail-calls like non-tail-calls, which gives you in error messages the location of the last call to the primitive which detected the error.
Marc