unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* gh_inexact_p error in 1.7.x
@ 2005-12-01  0:16 Bruce Korb
  2005-12-01  0:44 ` Kevin Ryde
  0 siblings, 1 reply; 32+ messages in thread
From: Bruce Korb @ 2005-12-01  0:16 UTC (permalink / raw)



Hi Rob et al.,

Now for something completely different.  Obviously, I have not yet
updated my code to figure out what sort of thing it is that I got
back from my eval call.  Nevertheless, my understanding was that
you ought to be able to call WHATEVER_p with any bit pattern and
have it say, "Yes, it is" or "No, it is not" without a fail-exit.
Not true in Guile 1.7.2.  Is this fixed?  Thanks!  - Bruce

typ = (SCM) 0x504

 	28	LOCAL teGuileType
 	29	gh_type_e( SCM typ )
-	30	{
-	31	    if (gh_boolean_p(    typ ))   return GH_TYPE_BOOLEAN;
-	32	    if (gh_symbol_p(     typ ))   return GH_TYPE_SYMBOL;
-	33	    if (gh_char_p(       typ ))   return GH_TYPE_CHAR;
-	34	    if (gh_vector_p(     typ ))   return GH_TYPE_VECTOR;
-	35	    if (gh_pair_p(       typ ))   return GH_TYPE_PAIR;
-	36	    if (gh_number_p(     typ ))   return GH_TYPE_NUMBER;
-	37	    if (AG_SCM_STRING_P( typ ))   return GH_TYPE_STRING;
-	38	    if (gh_procedure_p(  typ ))   return GH_TYPE_PROCEDURE;
-	39	    if (gh_list_p(       typ ))   return GH_TYPE_LIST;
-	40	    if (gh_inexact_p(    typ ))   return GH_TYPE_INEXACT;  <<=== throws error
-	41	    if (gh_exact_p(      typ ))   return GH_TYPE_EXACT;
 	42	
-	43	    return GH_TYPE_UNDEFINED;
-	44	}


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: gh_inexact_p error in 1.7.x
  2005-12-01  0:16 gh_inexact_p error in 1.7.x Bruce Korb
@ 2005-12-01  0:44 ` Kevin Ryde
  2005-12-05  4:08   ` No way out Bruce Korb
  0 siblings, 1 reply; 32+ messages in thread
From: Kevin Ryde @ 2005-12-01  0:44 UTC (permalink / raw)
  Cc: guile-devel

Bruce Korb <bkorb@gnu.org> writes:
>
> -	40	    if (gh_inexact_p(    typ ))   return GH_TYPE_INEXACT;  <<=== throws error

Collateral damage from the change to scm_inexact_p (other message).
Not sure how one or both ought to work.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-01  0:44 ` Kevin Ryde
@ 2005-12-05  4:08   ` Bruce Korb
  2005-12-05  4:35     ` Bruce Korb
                       ` (2 more replies)
  0 siblings, 3 replies; 32+ messages in thread
From: Bruce Korb @ 2005-12-05  4:08 UTC (permalink / raw)


On Wednesday 30 November 2005 04:44 pm, Kevin Ryde wrote:
> Collateral damage from the change to scm_inexact_p (other message).
> Not sure how one or both ought to work.

All *_p functions ought to accept anything without throwing an error.
Even if it doesn't seem to make sense.  That way, I know I don't have
to validate before calling a validation routine.  :-}

Anyway,  *real bugs* in Guile 1.7.2 are:

1.  When an error is thrown, "exit" should be called with EXIT_FAILURE, not 0.

2.  After these commands:

    (use-modules (ice-9 stack-catch))
    (debug-enable 'backtrace)

    I should be getting stack traces on Scheme errors.  I'm not.
    (And, yes, I invoke either ``(backtrace)'' or ``scm_backtrace()''
    when a failure is detected.)

3.  Either of these two implementations:

    port = scm_open_input_string( AG_SCM_STR02SCM( pzExpr ));
#if GUILE_VERSION < 107000
    {
        static SCM   file = SCM_UNDEFINED;
        static char* pzFl = NULL;
        scm_t_port*  pt;
        if (  (pzFl == NULL)
           || (strcmp( AG_SCM_CHARS( file ), pzFile ) != 0) )  {
            if (pzFl != NULL)
                free(pzFl);
            pzFl = strdup( pzFile );
            file = AG_SCM_STR02SCM( pzFile );
        }
        pt = SCM_PTAB_ENTRY(port);
        pt->line_number = line - 1;
        pt->file_name   = file;
    }
#else
    {
        static SCM file = SCM_UNDEFINED;
        static char* pzOldFile = NULL;
        if ((pzOldFile == NULL) || (strcmp( pzOldFile, pzFile ) != 0)) {
            if (pzOldFile != NULL)
                free( pzOldFile );
            pzOldFile = strdup( pzFile );
            file = scm_from_locale_string( pzFile );
        }
        scm_set_port_filename_x( port, file );
    }
    {
        SCM ln = scm_from_int( line );
        scm_set_port_line_x( port, ln );
    }
#endif

    should be enabling file and line numbers in errors.  I've tried both methods
    with 1.7 (and some others suggested in the discussion), to no avail.  I can
    get file and line information for 1.6.7 and earlier *only*.  There seems to
    be no way to do it in 1.7.

Thanks for your help!  Regards, Bruce


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-05  4:08   ` No way out Bruce Korb
@ 2005-12-05  4:35     ` Bruce Korb
  2005-12-07  1:31       ` Marius Vollmer
  2005-12-05 22:20     ` Kevin Ryde
  2005-12-07  1:07     ` No way out Marius Vollmer
  2 siblings, 1 reply; 32+ messages in thread
From: Bruce Korb @ 2005-12-05  4:35 UTC (permalink / raw)


On Sunday 04 December 2005 08:08 pm, Bruce Korb wrote:

> Anyway,  *real bugs* in Guile 1.7.2 are:
> 
> 1.  When an error is thrown, "exit" should be called with EXIT_FAILURE, not 0.

The problem here is that the doc for "gh_enter()" (and successors?) says
that it does not return.  It does.  The error handling long jumps around
my inner main and returns back to real main.  Oops.

 -- Function: void gh_enter (int ARGC, char *ARGV[], void
          (*MAIN_PROG)(int, char**))
     Starts up a Scheme interpreter with all the builtin Scheme
     primitives.  `gh_enter()' never exits, and the user's code should
     all be in the `MAIN_PROG()' function.  `argc' and `argv' will be
     passed to MAIN_PROG.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-05  4:08   ` No way out Bruce Korb
  2005-12-05  4:35     ` Bruce Korb
@ 2005-12-05 22:20     ` Kevin Ryde
  2005-12-06 10:58       ` Han-Wen Nienhuys
  2005-12-07  1:07     ` No way out Marius Vollmer
  2 siblings, 1 reply; 32+ messages in thread
From: Kevin Ryde @ 2005-12-05 22:20 UTC (permalink / raw)
  Cc: guile-devel

Bruce Korb <bkorb@gnu.org> writes:
>
>     I should be getting stack traces on Scheme errors.  I'm not.
>     (And, yes, I invoke either ``(backtrace)'' or ``scm_backtrace()''
>     when a failure is detected.)

I think I've been having trouble with backtraces not appearing too
(just from plain scheme code) but I didn't know where to look for
what's wrong.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-05 22:20     ` Kevin Ryde
@ 2005-12-06 10:58       ` Han-Wen Nienhuys
  2005-12-28 15:59         ` Neil Jerram
  0 siblings, 1 reply; 32+ messages in thread
From: Han-Wen Nienhuys @ 2005-12-06 10:58 UTC (permalink / raw)
  Cc: guile-devel

Kevin Ryde wrote:
> Bruce Korb <bkorb@gnu.org> writes:
> 
>>    I should be getting stack traces on Scheme errors.  I'm not.
>>    (And, yes, I invoke either ``(backtrace)'' or ``scm_backtrace()''
>>    when a failure is detected.)
> 
> 
> I think I've been having trouble with backtraces not appearing too
> (just from plain scheme code) but I didn't know where to look for
> what's wrong.

Backtraces haven't been appearing since I started using 1.7, for over a year

See also,

  http://lists.gnu.org/archive/html/guile-devel/2005-05/msg00010.html

-- 
  Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-05  4:08   ` No way out Bruce Korb
  2005-12-05  4:35     ` Bruce Korb
  2005-12-05 22:20     ` Kevin Ryde
@ 2005-12-07  1:07     ` Marius Vollmer
  2005-12-07  1:55       ` Rob Browning
  2005-12-28 16:09       ` Neil Jerram
  2 siblings, 2 replies; 32+ messages in thread
From: Marius Vollmer @ 2005-12-07  1:07 UTC (permalink / raw)
  Cc: guile-devel

Bruce Korb <bkorb@gnu.org> writes:

> Anyway,  *real bugs* in Guile 1.7.2 are:
>
> 1.  When an error is thrown, "exit" should be called with
>     EXIT_FAILURE, not 0.

I agree.  In 1.7.2, Guile no longer exits the whole program when an
uncaught error happens; it only exits the current thread with
"pthread_exit (NULL)".  If the current thread is the one running
'main', the process exits with return code 0.  Is there a way to
return an exit code with pthread_exit?

> 2.  After these commands:
>
>     (use-modules (ice-9 stack-catch))
>     (debug-enable 'backtrace)
>
>     I should be getting stack traces on Scheme errors.  I'm not.
>     (And, yes, I invoke either ``(backtrace)'' or ``scm_backtrace()''
>     when a failure is detected.)

Only "(debug-enable 'backtrace)" should be necessary.

However, you only get backtraces when the error happens from with the
usual read-eval-print-loop.  For example, this file

    (debug-enable 'backtrace)

    (define (foo)
      (+ 2 'a))

    (foo)

gives no backtrace when executed with

    $ guile -l x.scm

but you get a backtrace with

    $ guile
    guile> (load "x.scm")

And yes, this can be considered a bug, too... :-)

>     I can get file and line information for 1.6.7 and earlier
>     *only*.  There seems to be no way to do it in 1.7.

I will come back to this.

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-05  4:35     ` Bruce Korb
@ 2005-12-07  1:31       ` Marius Vollmer
  0 siblings, 0 replies; 32+ messages in thread
From: Marius Vollmer @ 2005-12-07  1:31 UTC (permalink / raw)
  Cc: guile-devel

Bruce Korb <bkorb@gnu.org> writes:

> On Sunday 04 December 2005 08:08 pm, Bruce Korb wrote:
>
>> Anyway,  *real bugs* in Guile 1.7.2 are:
>> 
>> 1.  When an error is thrown, "exit" should be called with EXIT_FAILURE, not 0.
>
> The problem here is that the doc for "gh_enter()" (and successors?) says
> that it does not return.  It does.  The error handling long jumps around
> my inner main and returns back to real main.  Oops.

Oops, indeed!  I fixed this.

My previous explanation was wrong: there should be no uncaught throws
unless there is some ither bug in Guile.  scm_with_guile, which is now
the main function for initializing Guile, establishes a catch all (via
scm_with_continuation_barrier).  However, that catch all does not exit
with pthread_exit, it simply makes scm_with_guile return NULL.  Bad.

2005-12-07  Marius Vollmer  <mvo@zagadka.de>

	Reported by Bruce Korb:
	
	* init.c (invoke_main_func): Don't call exit here.  Throws that are
	only caught by scm_with_guile will bypass us and would cause
	scm_boot_guile to return erroneously.
	(scm_boot_guile): Expect scm_with_guile to return and call exit
	here, passing it an appropriate exit code.

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-07  1:07     ` No way out Marius Vollmer
@ 2005-12-07  1:55       ` Rob Browning
  2005-12-13 20:32         ` Marius Vollmer
  2005-12-28 16:09       ` Neil Jerram
  1 sibling, 1 reply; 32+ messages in thread
From: Rob Browning @ 2005-12-07  1:55 UTC (permalink / raw)
  Cc: Bruce Korb, guile-devel

Marius Vollmer <mvo@zagadka.de> writes:

> Is there a way to return an exit code with pthread_exit()?

Doesn't pthread allow that directly?

  Function: void pthread_exit (void *RETVAL)

Of course you have to pthread_join() to get the value.

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org; previously @cs.utexas.edu
GPG starting 2002-11-03 = 14DD 432F AE39 534D B592  F9A0 25C8 D377 8C7E 73A4


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-07  1:55       ` Rob Browning
@ 2005-12-13 20:32         ` Marius Vollmer
  0 siblings, 0 replies; 32+ messages in thread
From: Marius Vollmer @ 2005-12-13 20:32 UTC (permalink / raw)
  Cc: Bruce Korb, guile-devel

Rob Browning <rlb@defaultvalue.org> writes:

> Marius Vollmer <mvo@zagadka.de> writes:
>
>> Is there a way to return an exit code with pthread_exit()?
>
> Doesn't pthread allow that directly?
>
>   Function: void pthread_exit (void *RETVAL)
>
> Of course you have to pthread_join() to get the value.

Yes, but what if you do a pthread_exit from the last thread of the
process?  Who is joining that?

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-06 10:58       ` Han-Wen Nienhuys
@ 2005-12-28 15:59         ` Neil Jerram
  2005-12-31 15:09           ` Han-Wen Nienhuys
  0 siblings, 1 reply; 32+ messages in thread
From: Neil Jerram @ 2005-12-28 15:59 UTC (permalink / raw)
  Cc: guile-devel

Han-Wen Nienhuys <hanwen@xs4all.nl> writes:

> Backtraces haven't been appearing since I started using 1.7, for over a year

Because of my interest in Guile's debugging infrastructure, I'd like
to understand and fix this.  Your statement is a bit vague, though,
unless you mean _only_ the following.

> See also,
>
>   http://lists.gnu.org/archive/html/guile-devel/2005-05/msg00010.html

As http://lists.gnu.org/archive/html/guile-devel/2005-05/msg00019.html
already asked (and to which there appears to be no reply), were you
running with the debugging evaluator (in other words (debug-enable
'debug))?  If not, does it help to say (debug-enable 'debug) as well
as (debug-enable 'backtrace)?

Regards,
        Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-07  1:07     ` No way out Marius Vollmer
  2005-12-07  1:55       ` Rob Browning
@ 2005-12-28 16:09       ` Neil Jerram
  1 sibling, 0 replies; 32+ messages in thread
From: Neil Jerram @ 2005-12-28 16:09 UTC (permalink / raw)
  Cc: Bruce Korb, guile-devel

Marius Vollmer <mvo@zagadka.de> writes:

> Bruce Korb <bkorb@gnu.org> writes:
>
>> 2.  After these commands:
>>
>>     (use-modules (ice-9 stack-catch))
>>     (debug-enable 'backtrace)
>>
>>     I should be getting stack traces on Scheme errors.  I'm not.
>>     (And, yes, I invoke either ``(backtrace)'' or ``scm_backtrace()''
>>     when a failure is detected.)
>
> Only "(debug-enable 'backtrace)" should be necessary.

And (debug-enable 'debug) or equivalent, I think.

>>     I can get file and line information for 1.6.7 and earlier
>>     *only*.  There seems to be no way to do it in 1.7.
>
> I will come back to this.

I think I've seen some places in eval.c where Dirk's recent
enhancements seemed to me to be discarding source info (by creating a
new pair instead of setting car and cdr, I think).  Is that what you
had in mind, or was there something else?

Regards,
        Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-28 15:59         ` Neil Jerram
@ 2005-12-31 15:09           ` Han-Wen Nienhuys
  2005-12-31 15:14             ` Neil Jerram
  0 siblings, 1 reply; 32+ messages in thread
From: Han-Wen Nienhuys @ 2005-12-31 15:09 UTC (permalink / raw)
  Cc: guile-devel

Neil Jerram wrote:
> Han-Wen Nienhuys <hanwen@xs4all.nl> writes:
> 
> 
>>Backtraces haven't been appearing since I started using 1.7, for over a year
> 
> 
> Because of my interest in Guile's debugging infrastructure, I'd like
> to understand and fix this.  Your statement is a bit vague, though,
> unless you mean _only_ the following.
> 
> 
>>See also,
>>
>>  http://lists.gnu.org/archive/html/guile-devel/2005-05/msg00010.html
> 
> 
> As http://lists.gnu.org/archive/html/guile-devel/2005-05/msg00019.html
> already asked (and to which there appears to be no reply), were you
> running with the debugging evaluator (in other words (debug-enable
> 'debug))?  If not, does it help to say (debug-enable 'debug) as well
> as (debug-enable 'backtrace)?

No it doesn't.    I have


;;; General settings
;;; debugging evaluator is slower.  This should
;;; have a more sensible default.

(if (ly:get-option 'verbose)
     (begin
       (debug-enable 'debug)
       (debug-enable 'backtrace)
       (read-enable 'positions)))

near the top of the first .scm file, but lilypond --verbose doesn't 
produce any backtraces.

If you intend to look at this, then I can try to isolate it to a smaller 
   case.

-- 
  Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-31 15:09           ` Han-Wen Nienhuys
@ 2005-12-31 15:14             ` Neil Jerram
  2006-01-01 19:58               ` Han-Wen Nienhuys
  0 siblings, 1 reply; 32+ messages in thread
From: Neil Jerram @ 2005-12-31 15:14 UTC (permalink / raw)
  Cc: guile-devel

Han-Wen Nienhuys <hanwen@xs4all.nl> writes:

> No it doesn't.    I have
>
>
> ;;; General settings
> ;;; debugging evaluator is slower.  This should
> ;;; have a more sensible default.
>
> (if (ly:get-option 'verbose)
>      (begin
>        (debug-enable 'debug)
>        (debug-enable 'backtrace)
>        (read-enable 'positions)))
>
> near the top of the first .scm file, but lilypond --verbose doesn't
> produce any backtraces.

OK, thanks for confirming this.

> If you intend to look at this, then I can try to isolate it to a
> smaller  case.

Yes, please; I'm keen to understand this.  Or I can work from the
Lilypond code, if you can suggest a point to start from (such as where
the error occurs that you want backtrace for).

    Neil




_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2005-12-31 15:14             ` Neil Jerram
@ 2006-01-01 19:58               ` Han-Wen Nienhuys
  2006-01-02 15:42                 ` Neil Jerram
  0 siblings, 1 reply; 32+ messages in thread
From: Han-Wen Nienhuys @ 2006-01-01 19:58 UTC (permalink / raw)


In article <87hd8pb8o7.fsf@ossau.uklinux.net>,
Neil Jerram  <neil@ossau.uklinux.net> wrote:
>
>> If you intend to look at this, then I can try to isolate it to a
>> smaller  case.
>
>Yes, please; I'm keen to understand this.  Or I can work from the
>Lilypond code, if you can suggest a point to start from (such as where
>the error occurs that you want backtrace for).


For starters, we could figure out why --debug doesn't work. This is
for a current CVS GUILE


muurbloem:~/src/lilypond$ cat g.scm

(define (f x)
  (display "HI")
  zapp)

(define (g x)
  (x))



(g f)
muurbloem:~/src/lilypond$ guile --debug g.scm
ERROR: Wrong number of arguments to #<procedure f (x)>
muurbloem:~/src/lilypond$ guile g.scm
ERROR: Wrong number of arguments to #<procedure f (x)>
muurbloem:~/src/lilypond$ guile
(guile>

(load "g.scm")

Backtrace:
In unknown file:
   ?: 0* [primitive-load "g.scm"]
In g.scm:
  11: 1* [g #<procedure f (x)>]
   7: 2  [f]

g.scm:7:3: In procedure f in expression (x):
g.scm:7:3: Wrong number of arguments to #<procedure f (x)>
ABORT: (wrong-number-of-args)
guile>







_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2006-01-01 19:58               ` Han-Wen Nienhuys
@ 2006-01-02 15:42                 ` Neil Jerram
  2006-01-02 18:54                   ` Neil Jerram
  0 siblings, 1 reply; 32+ messages in thread
From: Neil Jerram @ 2006-01-02 15:42 UTC (permalink / raw)
  Cc: guile-devel

hanwen@byrd.xs4all.nl (Han-Wen Nienhuys) writes:

> For starters, we could figure out why --debug doesn't work.

Progress so far...

In 1.6.x, the backtrace and full error information is generated by
this code towards the end of scm_ithrow() for the case where there
isn't a matching catch:

  if (scm_is_null (winds))
    {
      scm_handle_by_message (NULL, key, args);
      abort ();
    }

The backtrace code is inside scm_handle_by_message.

In 1.7.x, we don't call scm_handle_by_message, because there is a
matching catch which was set up as part of scm_with_guile.  The C
backtrace after jumping back out to this catch is:

#0  scm_internal_catch (tag=0x1, body=0x40044850 <c_body>, 
    body_data=0xbffffbe0, handler=0x40044880 <c_handler>, 
    handler_data=0xbffffbe0) at throw.c:158
#1  0x4004482c in scm_i_with_continuation_barrier (body=0x1, body_data=0x1, 
    handler=0x1, handler_data=0x1) at continuations.c:336
#2  0x40044913 in scm_c_with_continuation_barrier (func=0x1, data=0x1)
    at continuations.c:378
#3  0x400b53a0 in scm_i_with_guile_and_parent (func=0x1, data=0x1, parent=0x1)
    at threads.c:645
#4  0x400b5350 in scm_with_guile (func=0x1, data=0x1) at threads.c:633
#5  0x400732a1 in scm_boot_guile (argc=1, argv=0x1, main_func=0x1, closure=0x1)
    at init.c:350
#6  0x080489c6 in main (argc=1, argv=0x1) at guile.c:74

So it looks like there needs to be some scm_handle_by_message-like
code somewhere in this call stack.  Investigation continuing...

     Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: No way out.
  2006-01-02 15:42                 ` Neil Jerram
@ 2006-01-02 18:54                   ` Neil Jerram
  2006-01-04 21:13                     ` Backtrace and enhanced catch Neil Jerram
  0 siblings, 1 reply; 32+ messages in thread
From: Neil Jerram @ 2006-01-02 18:54 UTC (permalink / raw)
  Cc: guile-devel

Neil Jerram <neil@ossau.uklinux.net> writes:

> In 1.7.x, we don't call scm_handle_by_message, because there is a
> matching catch which was set up as part of scm_with_guile.  The C
> backtrace after jumping back out to this catch is:
>
> #0  scm_internal_catch (tag=0x1, body=0x40044850 <c_body>, 
>     body_data=0xbffffbe0, handler=0x40044880 <c_handler>, 
>     handler_data=0xbffffbe0) at throw.c:158
> #1  0x4004482c in scm_i_with_continuation_barrier (body=0x1, body_data=0x1, 
>     handler=0x1, handler_data=0x1) at continuations.c:336
> #2  0x40044913 in scm_c_with_continuation_barrier (func=0x1, data=0x1)
>     at continuations.c:378
> #3  0x400b53a0 in scm_i_with_guile_and_parent (func=0x1, data=0x1, parent=0x1)
>     at threads.c:645
> #4  0x400b5350 in scm_with_guile (func=0x1, data=0x1) at threads.c:633
> #5  0x400732a1 in scm_boot_guile (argc=1, argv=0x1, main_func=0x1, closure=0x1)
>     at init.c:350
> #6  0x080489c6 in main (argc=1, argv=0x1) at guile.c:74

The problem is that the use of scm_internal_catch here means that the
stack is unwound before the code in c_handler can get at it.
c_handler has code in it that would print a backtrace if the stack was
still available, but it isn't; to be precise, the "else if
(SCM_JMPBUFP (jmpbuf))" code in scm_ithrow sets
scm_i_last_debug_frame() back to NULL before the catch handler is called.

I think the only really good fix for this would be to implement an
exception handling mechanism that doesn't rely on lazy catch, along
the lines of SRFI-34.  Then the exception handler could display the
backtrace.

Alternatively we could make a shorter term fix by adding a lazy catch
inside the scm_internal_catch, and using the lazy catch handler either
to display the backtrace directly, or to save off the stack so it can
be displayed later.  scm_internal_stack_catch does the latter, by
setting the value of the-last-stack, so we could use that, but would
it be correct for uses of with-continuation-barrier to overwrite
the-last-stack?  I'm not sure.

One other query/possibility...  Does with-continuation-barrier _have_
to include a (catch #t ...)?  If it didn't, there wouldn't be a catch
on the wind list, and so the exception would be caught and handled by
the fallback code in scm_ithrow(), as is the case for 1.6.

Thoughts?
        Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Backtrace and enhanced catch
  2006-01-02 18:54                   ` Neil Jerram
@ 2006-01-04 21:13                     ` Neil Jerram
  2006-01-14 12:41                       ` Neil Jerram
                                         ` (2 more replies)
  0 siblings, 3 replies; 32+ messages in thread
From: Neil Jerram @ 2006-01-04 21:13 UTC (permalink / raw)
  Cc: guile-devel

Neil Jerram <neil@ossau.uklinux.net> writes:

> I think the only really good fix for this would be to implement an
> exception handling mechanism that doesn't rely on lazy catch, along
> the lines of SRFI-34.

On second thoughts, after rereading SRFI-34, I don't think that's the
solution.  SRFI-34's with-exception-handler is so similar to Guile's
existing lazy-catch that it doesn't give us anything better than we
have already.

I have a solution in mind, however, which is to add an optional fourth
arg ("lazy-handler") to `catch' (and corresponding C APIs, such as
scm_internal_catch), whose effect is the same as what we currently use
lazy-catch for.  For the specific problem that motivated this
investigation - getting a backtrace out of "guile --debug g.scm" - we
can then use this lazy-handler arg to display a backtrace and full
error information.  The following text explains how I've reached this
conclusion.

Overall there are two approaches for capturing or displaying the stack
when an error occurs.  Either you have an enclosing call like
lazy-catch or with-exception-handler somewhere up the call stack,
which specifies a handler to run in the case that an error escapes
back up to that point.  Or you add a throw-hook or error-hook to the
implementation of throw or error, and add the stack handling code to
that hook.  The difference is that the enclosing call approach allows
code inbetween the lazy-catch and the error point to decide on a
different, more local strategy for handling the error, whereas the
hook approach doesn't.  I think it's clear that the enclosing call
approach is better, so will focus on that from here on, but in
principle we could provide both in Guile.  My proposal here doesn't
rule out adding a hook as well in future.

There is a problem, though, with both lazy-catch and
with-exception-handler (which are the current Guile and SRFI-34
implementations of the enclosing call approach).  On the one hand they
require the handler to execute a non-local jump: the lazy-catch doc
says that its handler must not return, and SRFI-34 says that the
handler's continuation is not defined; on the other hand they need to
ensure that this jump is not handled by the same handler again.  In
the SRFI-34 case this leads to a strange rule: the handler must be
executed in the dynamic context of the error, except with the current
with-exception-handler handler removed; and it is not clear what
happens in odd but possible cases where, for example, the jump is to a
location that is still inside the dynamic scope of the relevant
with-exception-handler expression. In the lazy-catch case the
implementation avoids the possibility of the jump being caught by the
same handler by unwinding the dynamic context - all except for the
call stack - back to the lazy-catch expression before it calls the
handler.  So the lazy-catch handler isn't in fact consistently lazy:
fluid values, for example, are not those in the context of the error,
but those back in the context of the lazy-catch expression.

Another (lesser) problem with lazy-catch and with-exception-handler is
that they are always used in practice in a particular pattern.  For
lazy-catch the pattern is

  (catch tag
    (lambda ()
      (lazy-catch tag thunk lazy-handler))
    catch-handler)

For with-exception-handler the pattern (as shown by all the examples
in SRFI-34) is

  (call/cc
    (lambda (k)
      (with-exception-handler
        (lambda (obj)
          ...
          (k 'exception))
        thunk)))

Why is this a problem?  Because it strongly suggests that these forms
are more general than is useful.  And there is a cost to this: a bit
more typing in Scheme, and in the case of Guile a lot more complexity
in the C code needed to set up a catch and lazy catch pair (which is
relevant to the backtrace problem).

We can solve both problems by merging the semantics of catch and
lazy-catch into a single form, an enhanced catch:

 -- Scheme Procedure: catch key thunk handler [lazy-handler]
     
     ... [existing documentation] ...

     If a LAZY-HANDLER is given and THUNK throws an exception that
     matches KEY, Guile calls the LAZY-HANDLER before unwinding the
     dynamic state and invoking the main HANDLER.  LAZY-HANDLER should
     be a procedure with the same signature as HANDLER, that is
     `(lambda (key . args))', and must return normally, in other words
     not call `throw' or a continuation.  It is typically used to save
     the stack at the point where the exception occurred, but can also
     query other parts of the dynamic state at that point, such as
     fluid values.

We would add the same facility to C APIs for setting up catches (with
regard for backward compatibility, of course), and then finally we can
use the modified API to set up a lazy-handler inside
scm_c_with_continuation_barrier() that will save the stack so that a
backtrace can be displayed (or just to display the backtrace directly,
perhaps).

We will also be able to provide a standard lazy-handler for displaying
a backtrace, in both Scheme and C, which I think will give us a nicer
answer to the recurring "how do I get error information" questions on
the mailing list than what we have now.

lazy-catch itself can be deprecated and eventually removed.  All the
lazy-catch uses in Guile's own code follow the pattern above and so
can be rewritten as an enhanced catch, except for one (in
ice-9/emacs.scm) which is incorrect anyway because it can return
normally.

Comments?  If no one objects I will implement this (and fix the
backtrace problem) over the next few weeks.

Regards,
        Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-01-04 21:13                     ` Backtrace and enhanced catch Neil Jerram
@ 2006-01-14 12:41                       ` Neil Jerram
  2006-01-22 13:47                         ` Marius Vollmer
  2006-01-16  8:38                       ` Ludovic Courtès
  2006-01-26 23:29                       ` Kevin Ryde
  2 siblings, 1 reply; 32+ messages in thread
From: Neil Jerram @ 2006-01-14 12:41 UTC (permalink / raw)
  Cc: guile-devel

Neil Jerram <neil@ossau.uklinux.net> writes:

> We can solve both problems by merging the semantics of catch and
> lazy-catch into a single form, an enhanced catch:
>
>  -- Scheme Procedure: catch key thunk handler [lazy-handler]

The main part of this patch is appended below, and I would appreciate
any comments that anyone may have before I finish it off (by
deprecating the old APIs, replacing uses of lazy-catch, and so on).

One point is that I have removed the "SCM_API" from the declaration of
scm_i_with_continuation_barrier.  My understanding is that
scm_i_with_continuation_barrier (like scm_i_* functions in general) is
a libguile-internal function and so does not need to be exported from
the libguile DLL in a Windows build (which is what SCM_API is for).

With this patch, I get the following results running g.scm with and
without --debug ...

neil@laruns:~$ guile-local --debug g.scm
Backtrace:
In unknown file:
   ?: 0* [primitive-load "g.scm"]
In g.scm:
   8: 1* [g #<procedure f (x)>]
   6: 2  [f]

g.scm:6:3: In procedure f in expression (x):
g.scm:6:3: Wrong number of arguments to #<procedure f (x)>
neil@laruns:~$ guile-local g.scm
ERROR: Wrong number of arguments to #<procedure f (x)>
neil@laruns:~$ 

... which I believe is what is wanted.

Regards,
        Neil

cvs diff: Diffing libguile
Index: libguile/continuations.c
===================================================================
RCS file: /cvsroot/guile/guile/guile-core/libguile/continuations.c,v
retrieving revision 1.60
diff -u -u -r1.60 continuations.c
--- libguile/continuations.c	23 May 2005 19:57:20 -0000	1.60
+++ libguile/continuations.c	14 Jan 2006 12:43:30 -0000
@@ -312,7 +312,9 @@
 scm_i_with_continuation_barrier (scm_t_catch_body body,
 				 void *body_data,
 				 scm_t_catch_handler handler,
-				 void *handler_data)
+				 void *handler_data,
+				 scm_t_catch_handler lazy_handler,
+				 void *lazy_handler_data)
 {
   SCM_STACKITEM stack_item;
   scm_i_thread *thread = SCM_I_CURRENT_THREAD;
@@ -333,9 +335,10 @@
   /* Call FUNC inside a catch all.  This is now guaranteed to return
      directly and exactly once.
   */
-  result = scm_internal_catch (SCM_BOOL_T,
-			       body, body_data,
-			       handler, handler_data);
+  result = scm_c_catch (SCM_BOOL_T,
+			body, body_data,
+			handler, handler_data,
+			lazy_handler, lazy_handler_data);
 
   /* Return to old continuation root.
    */
@@ -364,7 +367,6 @@
 c_handler (void *d, SCM tag, SCM args)
 {
   struct c_data *data = (struct c_data *)d;
-  scm_handle_by_message_noexit (NULL, tag, args);
   data->result = NULL;
   return SCM_UNSPECIFIED;
 }
@@ -376,7 +378,8 @@
   c_data.func = func;
   c_data.data = data;
   scm_i_with_continuation_barrier (c_body, &c_data,
-				   c_handler, &c_data);
+				   c_handler, &c_data,
+				   scm_handle_by_message_noexit, NULL);
   return c_data.result;
 }
 
@@ -394,7 +397,6 @@
 static SCM
 scm_handler (void *d, SCM tag, SCM args)
 {
-  scm_handle_by_message_noexit (NULL, tag, args);
   return SCM_BOOL_F;
 }
 
@@ -415,7 +417,8 @@
   struct scm_data scm_data;
   scm_data.proc = proc;
   return scm_i_with_continuation_barrier (scm_body, &scm_data,
-					  scm_handler, &scm_data);
+					  scm_handler, &scm_data,
+					  scm_handle_by_message_noexit, NULL);
 }
 #undef FUNC_NAME
 
Index: libguile/continuations.h
===================================================================
RCS file: /cvsroot/guile/guile/guile-core/libguile/continuations.h,v
retrieving revision 1.34
diff -u -u -r1.34 continuations.h
--- libguile/continuations.h	23 May 2005 19:57:20 -0000	1.34
+++ libguile/continuations.h	14 Jan 2006 12:43:30 -0000
@@ -92,10 +92,12 @@
 SCM_API void *scm_c_with_continuation_barrier (void *(*func)(void*), void *);
 SCM_API SCM scm_with_continuation_barrier (SCM proc);
 
-SCM_API SCM scm_i_with_continuation_barrier (scm_t_catch_body body,
-					     void *body_data,
-					     scm_t_catch_handler handler,
-					     void *handler_data);
+SCM scm_i_with_continuation_barrier (scm_t_catch_body body,
+				     void *body_data,
+				     scm_t_catch_handler handler,
+				     void *handler_data,
+				     scm_t_catch_handler lazy_handler,
+				     void *lazy_handler_data);
 
 SCM_API void scm_init_continuations (void);
 
Index: libguile/root.c
===================================================================
RCS file: /cvsroot/guile/guile/guile-core/libguile/root.c,v
retrieving revision 1.78
diff -u -u -r1.78 root.c
--- libguile/root.c	23 May 2005 19:57:21 -0000	1.78
+++ libguile/root.c	14 Jan 2006 12:43:31 -0000
@@ -121,7 +121,8 @@
 
   my_handler_data.run_handler = 0;
   answer = scm_i_with_continuation_barrier (body, body_data,
-					    cwdr_handler, &my_handler_data);
+					    cwdr_handler, &my_handler_data,
+					    NULL, NULL);
 
   scm_frame_end ();
 
Index: libguile/throw.c
===================================================================
RCS file: /cvsroot/guile/guile/guile-core/libguile/throw.c,v
retrieving revision 1.107
diff -u -u -r1.107 throw.c
--- libguile/throw.c	23 May 2005 19:57:21 -0000	1.107
+++ libguile/throw.c	14 Jan 2006 12:43:32 -0000
@@ -54,6 +54,8 @@
 #define SETJBJMPBUF(x, v)        (SCM_SET_CELL_WORD_1 ((x), (scm_t_bits) (v)))
 #define SCM_JBDFRAME(x)         ((scm_t_debug_frame *) SCM_CELL_WORD_2 (x))
 #define SCM_SETJBDFRAME(x, v)    (SCM_SET_CELL_WORD_2 ((x), (scm_t_bits) (v)))
+#define SCM_JBLAZY(x)           ((struct lazy_catch *) SCM_CELL_WORD_3 (x))
+#define SCM_SETJBLAZY(x, v)      (SCM_SET_CELL_WORD_3 ((x), (scm_t_bits) (v)))
 
 static int
 jmpbuffer_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
@@ -80,7 +82,7 @@
 }
 
 \f
-/* scm_internal_catch (the guts of catch) */
+/* scm_c_catch (the guts of catch) */
 
 struct jmp_buf_and_retval	/* use only on the stack, in scm_catch */
 {
@@ -89,10 +91,25 @@
   SCM retval;
 };
 
+/* This is the structure we use to store lazy handling information for
+   a regular catch, and put on the wind list for a lazy catch.  It
+   stores the lazy handler function to call, and the data pointer to
+   pass through to it.  It's not a Scheme closure, but it is a
+   function with data, so the term "closure" is appropriate in its
+   broader sense.
+
+   (We don't need anything like this to run the "eager" catch handler,
+   because the same C frame runs both the body and the handler.)  */
+
+struct lazy_catch {
+  scm_t_catch_handler handler;
+  void *handler_data;
+};
 
-/* scm_internal_catch is the guts of catch.  It handles all the
-   mechanics of setting up a catch target, invoking the catch body,
-   and perhaps invoking the handler if the body does a throw.
+
+/* scm_c_catch is the guts of catch.  It handles all the mechanics of
+   setting up a catch target, invoking the catch body, and perhaps
+   invoking the handler if the body does a throw.
 
    The function is designed to be usable from C code, but is general
    enough to implement all the semantics Guile Scheme expects from
@@ -138,17 +155,26 @@
    will be found.  */
 
 SCM
-scm_internal_catch (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data)
+scm_c_catch (SCM tag,
+	     scm_t_catch_body body, void *body_data,
+	     scm_t_catch_handler handler, void *handler_data,
+	     scm_t_catch_handler lazy_handler, void *lazy_handler_data)
 {
   struct jmp_buf_and_retval jbr;
   SCM jmpbuf;
   SCM answer;
+  struct lazy_catch lazy;
 
   jmpbuf = make_jmpbuf ();
   answer = SCM_EOL;
   scm_i_set_dynwinds (scm_acons (tag, jmpbuf, scm_i_dynwinds ()));
   SETJBJMPBUF(jmpbuf, &jbr.buf);
   SCM_SETJBDFRAME(jmpbuf, scm_i_last_debug_frame ());
+
+  lazy.handler = lazy_handler;
+  lazy.handler_data = lazy_handler_data;
+  SCM_SETJBLAZY(jmpbuf, &lazy);
+
   if (setjmp (jbr.buf))
     {
       SCM throw_tag;
@@ -179,6 +205,17 @@
   return answer;
 }
 
+SCM
+scm_internal_catch (SCM tag,
+		    scm_t_catch_body body, void *body_data,
+		    scm_t_catch_handler handler, void *handler_data)
+{
+  return scm_c_catch(tag,
+		     body, body_data,
+		     handler, handler_data,
+		     NULL, NULL);
+}
+
 
 \f
 /* scm_internal_lazy_catch (the guts of lazy catching) */
@@ -186,19 +223,6 @@
 /* The smob tag for lazy_catch smobs.  */
 static scm_t_bits tc16_lazy_catch;
 
-/* This is the structure we put on the wind list for a lazy catch.  It
-   stores the handler function to call, and the data pointer to pass
-   through to it.  It's not a Scheme closure, but it is a function
-   with data, so the term "closure" is appropriate in its broader
-   sense.
-
-   (We don't need anything like this in the "eager" catch code,
-   because the same C frame runs both the body and the handler.)  */
-struct lazy_catch {
-  scm_t_catch_handler handler;
-  void *handler_data;
-};
-
 /* Strictly speaking, we could just pass a zero for our print
    function, because we don't need to print them.  They should never
    appear in normal data structures, only in the wind list.  However,
@@ -490,8 +514,8 @@
 \f
 /* the Scheme-visible CATCH and LAZY-CATCH functions */
 
-SCM_DEFINE (scm_catch, "catch", 3, 0, 0,
-	    (SCM key, SCM thunk, SCM handler),
+SCM_DEFINE (scm_catch_with_lazy_handler, "catch", 3, 1, 0,
+	    (SCM key, SCM thunk, SCM handler, SCM lazy_handler),
 	    "Invoke @var{thunk} in the dynamic context of @var{handler} for\n"
 	    "exceptions matching @var{key}.  If thunk throws to the symbol\n"
 	    "@var{key}, then @var{handler} is invoked this way:\n"
@@ -509,8 +533,19 @@
 	    "from further up the call chain is invoked.\n"
 	    "\n"
 	    "If the key is @code{#t}, then a throw to @emph{any} symbol will\n"
-	    "match this call to @code{catch}.")
-#define FUNC_NAME s_scm_catch
+	    "match this call to @code{catch}.\n"
+	    "\n"
+	    "If a @var{lazy-handler} is given and @var{thunk} throws an\n"
+	    "exception that matches @var{key}, Guile calls the\n"
+	    "@var{lazy-handler} before unwinding the dynamic state and\n"
+	    "invoking the main @var{handler}.  @var{lazy-handler} should\n"
+	    "be a procedure with the same signature as @var{handler}, that\n"
+	    "is @code{(lambda (key . args))}, and should return normally, in\n"
+	    "other words not call @code{throw} or a continuation.  It is\n"
+	    "typically used to save the stack at the point where the\n"
+	    "exception occurred, but can also query other parts of the\n"
+	    "dynamic state at that point, such as fluid values.")
+#define FUNC_NAME s_scm_catch_with_lazy_handler
 {
   struct scm_body_thunk_data c;
 
@@ -520,17 +555,29 @@
   c.tag = key;
   c.body_proc = thunk;
 
-  /* scm_internal_catch takes care of all the mechanics of setting up
-     a catch key; we tell it to call scm_body_thunk to run the body,
-     and scm_handle_by_proc to deal with any throws to this catch.
-     The former receives a pointer to c, telling it how to behave.
-     The latter receives a pointer to HANDLER, so it knows who to call.  */
-  return scm_internal_catch (key,
-			     scm_body_thunk, &c, 
-			     scm_handle_by_proc, &handler);
+  /* scm_c_catch takes care of all the mechanics of setting up a catch
+     key; we tell it to call scm_body_thunk to run the body, and
+     scm_handle_by_proc to deal with any throws to this catch.  The
+     former receives a pointer to c, telling it how to behave.  The
+     latter receives a pointer to HANDLER, so it knows who to
+     call.  */
+  return scm_c_catch (key,
+		      scm_body_thunk, &c, 
+		      scm_handle_by_proc, &handler,
+		      SCM_UNBNDP (lazy_handler) ? NULL : scm_handle_by_proc,
+		      &lazy_handler);
 }
 #undef FUNC_NAME
 
+/* The following function exists to provide backwards compatibility
+   for the C scm_catch API.  Otherwise we could just change
+   "scm_catch_with_lazy_handler" above to "scm_catch". */
+SCM
+scm_catch (SCM key, SCM thunk, SCM handler)
+{
+  return scm_catch_with_lazy_handler (key, thunk, handler, SCM_UNDEFINED);
+}
+
 
 SCM_DEFINE (scm_lazy_catch, "lazy-catch", 3, 0, 0,
 	    (SCM key, SCM thunk, SCM handler),
@@ -646,7 +693,16 @@
   /* Otherwise, it's a normal catch.  */
   else if (SCM_JMPBUFP (jmpbuf))
     {
+      struct lazy_catch * lazy;
       struct jmp_buf_and_retval * jbr;
+
+      /* Before unwinding anything, run the lazy handler if there is
+	 one. */
+      lazy = SCM_JBLAZY (jmpbuf);
+      if (lazy->handler)
+	(lazy->handler) (lazy->handler_data, key, args);
+
+      /* Now unwind and jump. */
       scm_dowinds (wind_goal, (scm_ilength (scm_i_dynwinds ())
 			       - scm_ilength (wind_goal)));
       jbr = (struct jmp_buf_and_retval *)JBJMPBUF (jmpbuf);
Index: libguile/throw.h
===================================================================
RCS file: /cvsroot/guile/guile/guile-core/libguile/throw.h,v
retrieving revision 1.26
diff -u -u -r1.26 throw.h
--- libguile/throw.h	23 May 2005 19:57:21 -0000	1.26
+++ libguile/throw.h	14 Jan 2006 12:43:32 -0000
@@ -30,6 +30,14 @@
 typedef SCM (*scm_t_catch_handler) (void *data,
                                     SCM tag, SCM throw_args);
 
+SCM_API SCM scm_c_catch (SCM tag,
+			 scm_t_catch_body body,
+			 void *body_data,
+			 scm_t_catch_handler handler,
+			 void *handler_data,
+			 scm_t_catch_handler lazy_handler,
+			 void *lazy_handler_data);
+
 SCM_API SCM scm_internal_catch (SCM tag,
 				scm_t_catch_body body,
 				void *body_data,
@@ -72,6 +80,7 @@
 SCM_API SCM scm_handle_by_throw (void *, SCM, SCM);
 SCM_API int scm_exit_status (SCM args);
 
+SCM_API SCM scm_catch_with_lazy_handler (SCM tag, SCM thunk, SCM handler, SCM lazy_handler);
 SCM_API SCM scm_catch (SCM tag, SCM thunk, SCM handler);
 SCM_API SCM scm_lazy_catch (SCM tag, SCM thunk, SCM handler);
 SCM_API SCM scm_ithrow (SCM key, SCM args, int noreturn);
cvs diff: Diffing libguile-ltdl
cvs diff: Diffing libguile-ltdl/upstream
cvs diff: Diffing libltdl
cvs diff: Diffing oop
cvs diff: Diffing oop/goops
cvs diff: Diffing qt
cvs diff: Diffing qt/md
cvs diff: Diffing qt/time
cvs diff: Diffing scripts
cvs diff: Diffing srfi
cvs diff: Diffing test-suite
cvs diff: Diffing test-suite/standalone
cvs diff: Diffing test-suite/tests
Index: test-suite/tests/exceptions.test
===================================================================
RCS file: /cvsroot/guile/guile/guile-core/test-suite/tests/exceptions.test,v
retrieving revision 1.11
diff -u -u -r1.11 exceptions.test
--- test-suite/tests/exceptions.test	23 May 2005 19:57:22 -0000	1.11
+++ test-suite/tests/exceptions.test	14 Jan 2006 12:43:32 -0000
@@ -60,7 +60,25 @@
       exception:wrong-num-args
       (catch 'a
 	(lambda () (throw 'a))
-	(lambda (x y . rest) #f)))))
+	(lambda (x y . rest) #f))))
+
+  (with-test-prefix "with lazy handler"
+
+    (pass-if "lazy fluid state"
+      (equal? '(inner outer arg)
+       (let ((fluid-parm (make-fluid))
+	     (inner-val #f))
+	 (fluid-set! fluid-parm 'outer)
+	 (catch 'misc-exc
+	   (lambda ()
+	     (with-fluids ((fluid-parm 'inner))
+	       (throw 'misc-exc 'arg)))
+	   (lambda (key . args)
+	     (list inner-val
+		   (fluid-ref fluid-parm)
+		   (car args)))
+	   (lambda (key . args)
+	     (set! inner-val (fluid-ref fluid-parm)))))))))
 
 (with-test-prefix "false-if-exception"



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-01-04 21:13                     ` Backtrace and enhanced catch Neil Jerram
  2006-01-14 12:41                       ` Neil Jerram
@ 2006-01-16  8:38                       ` Ludovic Courtès
  2006-01-18 23:08                         ` Neil Jerram
  2006-01-26 23:29                       ` Kevin Ryde
  2 siblings, 1 reply; 32+ messages in thread
From: Ludovic Courtès @ 2006-01-16  8:38 UTC (permalink / raw)
  Cc: hanwen, guile-devel

Hi,

Better late than never...  ;-)

Neil Jerram <neil@ossau.uklinux.net> writes:

> Another (lesser) problem with lazy-catch and with-exception-handler is
> that they are always used in practice in a particular pattern.  For
> lazy-catch the pattern is
>
>   (catch tag
>     (lambda ()
>       (lazy-catch tag thunk lazy-handler))
>     catch-handler)
>
> For with-exception-handler the pattern (as shown by all the examples
> in SRFI-34) is
>
>   (call/cc
>     (lambda (k)
>       (with-exception-handler
>         (lambda (obj)
>           ...
>           (k 'exception))
>         thunk)))
>
> Why is this a problem?  Because it strongly suggests that these forms
> are more general than is useful.  And there is a cost to this: a bit
> more typing in Scheme, and in the case of Guile a lot more complexity
> in the C code needed to set up a catch and lazy catch pair (which is
> relevant to the backtrace problem).

OTOH, this would suggest that `lazy-catch' and `call/cc' are all we need
to implement `catch'.  This is probably the reason why SRFI-34 defines
no construct equivalent to `catch'.

>From a theoretical viewpoint, it seems to me that it would make sense to
just keep `lazy-catch' as a primitive and have `catch' implemented as a
macro on top of it.  Now, from Guile's implementation viewpoint, I guess
it would be much more costly/complex as you said.

Anyway, thanks for your patch: it's nice to see this issue is going to
be fixed! ;-)  And sorry for not replying earlier.

Ludovic.



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-01-16  8:38                       ` Ludovic Courtès
@ 2006-01-18 23:08                         ` Neil Jerram
  2006-01-19  9:38                           ` Ludovic Courtès
  0 siblings, 1 reply; 32+ messages in thread
From: Neil Jerram @ 2006-01-18 23:08 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> Hi,
>
> Better late than never...  ;-)

Absolutely!

> Neil Jerram <neil@ossau.uklinux.net> writes:
>
>> Another (lesser) problem with lazy-catch and with-exception-handler is
>> that they are always used in practice in a particular pattern. [...]
>
> OTOH, this would suggest that `lazy-catch' and `call/cc' are all we need
> to implement `catch'.

Theoretically, perhaps.  But if you accept the gist of my analysis,
that would be to build something that has nice clear semantics (catch)
on top of something that has rather awkward semantics (lazy-catch),
which doesn't seem sensible.

And for Guile (as a particular Scheme implementation) there is a
further reason against this, namely the runtime cost of call/cc.
catch in Guile is much more efficient than code using call/cc to do
the same thing.

>  This is probably the reason why SRFI-34 defines
> no construct equivalent to `catch'.

Actually it does; the `guard' syntax is pretty close to catch.

(BTW, in connection with `guard', which was called `try' in the
original draft of SRFI 34, I came across this email in the discussion
archive: http://srfi.schemers.org/srfi-34/mail-archive/msg00013.html.
This email concludes:

    Robust and portable code should only use the "try" form.

for reasons connected to how dynamic state is handled that I think are
similar to the reasoning in my analysis.

If accepted, this conclusion leaves SRFI-34 incomplete, because
try/guard provides no way of running something in the context of the
original error.)

>>From a theoretical viewpoint, it seems to me that it would make sense to
> just keep `lazy-catch' as a primitive and have `catch' implemented as a
> macro on top of it.  Now, from Guile's implementation viewpoint, I guess
> it would be much more costly/complex as you said.

Yes; as well as my points above, we'd like to have something that is
easy to use in the C API.

> Anyway, thanks for your patch: it's nice to see this issue is going to
> be fixed! ;-)  And sorry for not replying earlier.

Thanks for your comments.

       Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-01-18 23:08                         ` Neil Jerram
@ 2006-01-19  9:38                           ` Ludovic Courtès
  2006-01-21 11:26                             ` Neil Jerram
  0 siblings, 1 reply; 32+ messages in thread
From: Ludovic Courtès @ 2006-01-19  9:38 UTC (permalink / raw)
  Cc: guile-devel

Neil Jerram <neil@ossau.uklinux.net> writes:

> Theoretically, perhaps.  But if you accept the gist of my analysis,
> that would be to build something that has nice clear semantics (catch)
> on top of something that has rather awkward semantics (lazy-catch),
> which doesn't seem sensible.

Yes, but internally, there is necessarily some form of `lazy-catch',
i.e., there is code that executes just after the exception was raised
and just before the stack is unwound.  So it seems that `catch' is just
hiding this away.

OTOH, you comments about the environment in which the `lazy-catch'
handler gets run, the fact that it must not return, etc., make it clear
why it deserves the qualification of "awkward semantics".  ;-)

> And for Guile (as a particular Scheme implementation) there is a
> further reason against this, namely the runtime cost of call/cc.
> catch in Guile is much more efficient than code using call/cc to do
> the same thing.

Agreed.

> Actually it does; the `guard' syntax is pretty close to catch.

Right, I had misunderstood `guard'.

> (BTW, in connection with `guard', which was called `try' in the
> original draft of SRFI 34, I came across this email in the discussion
> archive: http://srfi.schemers.org/srfi-34/mail-archive/msg00013.html.
> This email concludes:
>
>     Robust and portable code should only use the "try" form.
>
> for reasons connected to how dynamic state is handled that I think are
> similar to the reasoning in my analysis.
>
> If accepted, this conclusion leaves SRFI-34 incomplete, because
> try/guard provides no way of running something in the context of the
> original error.)

Well, you still have `with-exception-handler', except that it must be
used carefully.

In the light of your comments, it looks like your patch is the way to
go!

Thanks,
Ludovic.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-01-19  9:38                           ` Ludovic Courtès
@ 2006-01-21 11:26                             ` Neil Jerram
  0 siblings, 0 replies; 32+ messages in thread
From: Neil Jerram @ 2006-01-21 11:26 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> Yes, but internally, there is necessarily some form of `lazy-catch',

Not exactly, no.

> i.e., there is code that executes just after the exception was raised
> and just before the stack is unwound.

Yes, there is such code, but this is just part of what `lazy-catch' as
a whole needs to do.

>  So it seems that `catch' is just hiding this away.

`Hiding' is a loaded word.  I would agree that `catch' is
encapsulating the running of this code.  The whole point of my
analysis is that this is a good thing.

>> (BTW, in connection with `guard', which was called `try' in the
>> original draft of SRFI 34, I came across this email in the discussion
>> archive: http://srfi.schemers.org/srfi-34/mail-archive/msg00013.html.
>> This email concludes:
>>
>>     Robust and portable code should only use the "try" form.
>>
>> for reasons connected to how dynamic state is handled that I think are
>> similar to the reasoning in my analysis.
>>
>> If accepted, this conclusion leaves SRFI-34 incomplete, because
>> try/guard provides no way of running something in the context of the
>> original error.)
>
> Well, you still have `with-exception-handler', except that it must be
> used carefully.

When I wrote "If accepted", I meant "If you agree that `robust and
portable code should only use the try form'", which implies that
with-exception-handler should not be used.

Thanks for your comments on this!

Regards,
        Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-01-14 12:41                       ` Neil Jerram
@ 2006-01-22 13:47                         ` Marius Vollmer
  2006-01-23 20:11                           ` Neil Jerram
  0 siblings, 1 reply; 32+ messages in thread
From: Marius Vollmer @ 2006-01-22 13:47 UTC (permalink / raw)
  Cc: hanwen, guile-devel

Neil Jerram <neil@ossau.uklinux.net> writes:

> The main part of this patch is appended below, and I would appreciate
> any comments that anyone may have 

Looks very good to me.  Please go ahead.  Thanks!

One (minor?) point I have is the term "lazy".  I am not sure if it is
the right term to use.  It has meaning for people who already know
lazy-catch, but I'd say it is not really descriptive of what it does.
Something like "pre-unwind" handler might give a better hint of how it
differs from the 'post-unwind' handler.

Hmm, what I'm trying to say here that "lazy" is not some standard,
established terminology, and if we come up with something better, we
should feel free to change terminology.

> One point is that I have removed the "SCM_API" from the declaration of
> scm_i_with_continuation_barrier.  My understanding is that
> scm_i_with_continuation_barrier (like scm_i_* functions in general) is
> a libguile-internal function and so does not need to be exported from
> the libguile DLL in a Windows build (which is what SCM_API is for).

Yeah.  I have to say that I don't really understand the meaning of
SCM_API.  I mostly treat it is as a purely technical thing: you need
to use it when you want code outside this DLL to call the function.  I
don't treat it as a way to document what is in the Guile API and what
isn't.

For example, a macro or inline function that is in the Guile API might
expand into a call to a scm_i_ function.  That function than needs to
be flagged with SCM_API although it is not part of the API.

I see no point in preventing people from calling internal functions as
long as they know that they are internal.  That's why I put SCM_API on
all functions with global scope.

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-01-22 13:47                         ` Marius Vollmer
@ 2006-01-23 20:11                           ` Neil Jerram
  2006-01-24 21:34                             ` Marius Vollmer
  0 siblings, 1 reply; 32+ messages in thread
From: Neil Jerram @ 2006-01-23 20:11 UTC (permalink / raw)
  Cc: hanwen, guile-devel

Marius Vollmer <mvo@zagadka.de> writes:

> Neil Jerram <neil@ossau.uklinux.net> writes:
>
>> The main part of this patch is appended below, and I would appreciate
>> any comments that anyone may have 
>
> Looks very good to me.  Please go ahead.  Thanks!

Great; thanks for the review.

> One (minor?) point I have is the term "lazy".  I am not sure if it is
> the right term to use.  It has meaning for people who already know
> lazy-catch, but I'd say it is not really descriptive of what it does.
> Something like "pre-unwind" handler might give a better hint of how it
> differs from the 'post-unwind' handler.
>
> Hmm, what I'm trying to say here that "lazy" is not some standard,
> established terminology, and if we come up with something better, we
> should feel free to change terminology.

Yes, that makes good sense.  I can't think of anything better than
"pre-unwind", so I'll use that in all new names.  I don't think it's
worth changing any preexisting names though, such as struct lazy_catch
- do you agree?

>> One point is that I have removed the "SCM_API" from the declaration of
>> scm_i_with_continuation_barrier.  My understanding is that
>> scm_i_with_continuation_barrier (like scm_i_* functions in general) is
>> a libguile-internal function and so does not need to be exported from
>> the libguile DLL in a Windows build (which is what SCM_API is for).
>
> Yeah.  I have to say that I don't really understand the meaning of
> SCM_API.  I mostly treat it is as a purely technical thing: you need
> to use it when you want code outside this DLL to call the function.  I
> don't treat it as a way to document what is in the Guile API and what
> isn't.
>
> For example,  macro or inline function that is in the Guile API might
> expand into a call to a scm_i_ function.  That function than needs to
> be flagged with SCM_API although it is not part of the API.
>
> I see no point in preventing people from calling internal functions as
> long as they know that they are internal.  That's why I put SCM_API on
> all functions with global scope.

OK, that makes sense too, so long as we don't have to worry about
preserving source compatibility for functions that have SCM_API but
are not part of the Guile API.  And my understanding is that "part of
the Guile API" <=> "documented in the manual".

Regards,
        Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-01-23 20:11                           ` Neil Jerram
@ 2006-01-24 21:34                             ` Marius Vollmer
  0 siblings, 0 replies; 32+ messages in thread
From: Marius Vollmer @ 2006-01-24 21:34 UTC (permalink / raw)
  Cc: hanwen, guile-devel

>> Hmm, what I'm trying to say here that "lazy" is not some standard,
>> established terminology, and if we come up with something better, we
>> should feel free to change terminology.
>
> Yes, that makes good sense.  I can't think of anything better than
> "pre-unwind", so I'll use that in all new names.  I don't think it's
> worth changing any preexisting names though, such as struct lazy_catch
> - do you agree?

I agree.

> [...], so long as we don't have to worry about preserving source
> compatibility for functions that have SCM_API but are not part of
> the Guile API.  And my understanding is that "part of the Guile API"
> <=> "documented in the manual".

Yes, exactly.

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-01-04 21:13                     ` Backtrace and enhanced catch Neil Jerram
  2006-01-14 12:41                       ` Neil Jerram
  2006-01-16  8:38                       ` Ludovic Courtès
@ 2006-01-26 23:29                       ` Kevin Ryde
  2006-01-27 19:30                         ` Neil Jerram
  2 siblings, 1 reply; 32+ messages in thread
From: Kevin Ryde @ 2006-01-26 23:29 UTC (permalink / raw)


Neil Jerram <neil@ossau.uklinux.net> writes:
>
> The difference is that the enclosing call approach allows
> code inbetween the lazy-catch and the error point to decide on a
> different, more local strategy for handling the error, whereas the
> hook approach doesn't.  I think it's clear that the enclosing call
> approach is better,

Yes.  Making a local decision is what I always seem to use lazy-catch
for, in my case trapping selected system call errors but not
interfering with the backtrace of others.

> the lazy-catch doc says that its handler must not return,

It'd be nice if that could be relaxed, if it was easy to do.  In a
couple of places I've wanted to return and continue past the
lazy-catch form, having taken whatever action in the handler.  (An
extra wrapping full `catch' makes that possible.)


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-01-26 23:29                       ` Kevin Ryde
@ 2006-01-27 19:30                         ` Neil Jerram
  2006-01-31 20:07                           ` Kevin Ryde
  0 siblings, 1 reply; 32+ messages in thread
From: Neil Jerram @ 2006-01-27 19:30 UTC (permalink / raw)


Kevin Ryde <user42@zip.com.au> writes:

> Neil Jerram <neil@ossau.uklinux.net> writes:
>>
>> The difference is that the enclosing call approach allows
>> code inbetween the lazy-catch and the error point to decide on a
>> different, more local strategy for handling the error, whereas the
>> hook approach doesn't.  I think it's clear that the enclosing call
>> approach is better,
>
> Yes.  Making a local decision is what I always seem to use lazy-catch
> for, in my case trapping selected system call errors but not
> interfering with the backtrace of others.

Not sure I understand.  Can you point me to an example?

>> the lazy-catch doc says that its handler must not return,
>
> It'd be nice if that could be relaxed, if it was easy to do.  In a
> couple of places I've wanted to return and continue past the
> lazy-catch form, having taken whatever action in the handler.  (An
> extra wrapping full `catch' makes that possible.)

Can you give an example to show what you mean?  I think it's
non-negotiable that if someone has coded a (throw ...) or an (error
...), execution cannot continue normally past that throw or error -
but perhaps that's not what you meant?

Regards,
        Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-01-27 19:30                         ` Neil Jerram
@ 2006-01-31 20:07                           ` Kevin Ryde
  2006-02-01 23:04                             ` Neil Jerram
  0 siblings, 1 reply; 32+ messages in thread
From: Kevin Ryde @ 2006-01-31 20:07 UTC (permalink / raw)
  Cc: guile-devel

Neil Jerram <neil@ossau.uklinux.net> writes:
>
> an example?

    (c-lazy-catch #t

      (lambda ()
        (mucho hairy data download using http, including continuations
         to suspend))

      (lambda args
        (print-message "%s and %s went wrong" ...)

        ;; continue on connection or http protocol problems (including
        ;; http timeout), throw full error otherwise
        (if (not (or (eq? 'http (first args))         ;; my errors
                     (gethost-error-try-again? args)  ;; gethost errors
                     (system-error-econn? args)))     ;; ECONNREFUSED
            (apply throw args))))

The idea is the handler does some cleanup (print a message in this
case) and then makes a decision about continuing or dying.  If it's
fatal then re-throw, and in that throw I'm wanting a full backtrace.

If this was a plain `catch' then the re-throw loses the backtrace, and
if it was a lazy-catch then you're not allowed to return, hence my
c-lazy-catch which is a combination.  The implementation isn't
super-efficient,

    ;; lazy-catch, but with HANDLER allowed to return
    (define-public (c-lazy-catch key thunk handler)
      (catch 'c-lazy-catch
        (lambda ()
          (lazy-catch key thunk
                      (lambda args
                        (throw 'c-lazy-catch (apply handler args)))))
        (lambda (key val)
          val)))

I'm not sure how typical this is.  It seems a reasonable desire, but
maybe there's a better way to do it.  I've fiddled about a bit with my
overall error trap structure, from trapping each call to now a higher
level overall catch.

> I think it's non-negotiable that if someone has coded a (throw ...)
> or an (error ...), execution cannot continue normally past that
> throw or error

Yes, that'd create havoc, I only meant continue after the `catch' /
`lazy-catch' form.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-01-31 20:07                           ` Kevin Ryde
@ 2006-02-01 23:04                             ` Neil Jerram
  2006-02-04  0:46                               ` Kevin Ryde
  0 siblings, 1 reply; 32+ messages in thread
From: Neil Jerram @ 2006-02-01 23:04 UTC (permalink / raw)


Kevin Ryde <user42@zip.com.au> writes:

>     ;; lazy-catch, but with HANDLER allowed to return
>     (define-public (c-lazy-catch key thunk handler)
>       (catch 'c-lazy-catch
>         (lambda ()
>           (lazy-catch key thunk
>                       (lambda args
>                         (throw 'c-lazy-catch (apply handler args)))))
>         (lambda (key val)
>           val)))

Thanks.  It took me a while to get my head round this, but in the end
it has helped me see how we can put some finishing touches to
catch and lazy-catch so that they are really nice, clear, consistent
and useful.

With these finishing touches, I think you would be able to write
c-lazy-catch as:

(define (c-lazy-catch key thunk handler)
  (catch key
         thunk
         noop
         handler))

The spec for catch's pre-unwind-handler would be that it can exit
either normally or non-locally.  If it exits normally, Guile unwinds
(dynamic context + stack) and then calls the normal (post-unwind)
handler.  If it exits non-locally, that exit determines the
continuation.

The spec for a lazy-catch handler would be nicely consistent with
this.  Again, we say that the lazy-catch handler can exit either
normally or non-locally.  It if exits normally, Guile itself throws
the same key and args again.  If it exits non-locally, that exit
determines the continuation.

For both cases, we need to make sure that a pre-unwind or lazy-catch
handler that rethrows (or, more generally, throws something whose key
matches its own catch/lazy-catch) does not call the same pre-unwind or
lazy-catch handler again recursively.  (For two reasons: first, to
avoid a possible infinite recursion; second, to allow an interesting
new behaviour, chained calling of lazy-catch/pre-unwind handlers up
the dynamic context.)  Guile currently does this by unwinding the
dynamic context before calling the handler, but this has the problem
that the handler does not truly run in the context where the throw
occurred.  Instead of that, we can avoid the recursion quite easily by
adding a "running" field to the lazy_catch/pre_unwind structure, and
using the scm_frame_ API to ensure that this is set when the handler
is running and reset when it is exited (either normally or
non-locally).

Existing lazy-catch handlers usually end with `(apply throw key args)'
to do a rethrow.  A nice consequence of the spec and implementation
just proposed is that such a handler (if it exits by this throw) will
behave exactly the same as if this final expression was not there.

If we implement this under the existing lazy-catch interface, there
would be 3 kinds of incompatible behaviour change.

1. A lazy-catch handler that returns normally would be equivalent to
   ending with a rethrow, whereas currently Guile does a
   scm_misc_error ("throw", "lazy-catch handler did return.",
   SCM_EOL);

2. Lazy-catch handlers would execute in the full dynamic context where
   the throw occurred, including in particular fluid values; whereas
   currently they don't.  (The only bit of dynamic context that the
   current implementation preserves is the stack.)

3. If a lazy-catch handler throws to a key that does not match its own
   lazy-catch, the proposed new implementation could match that key to
   a catch/lazy-catch that is _closer_ to the throw than the first
   lazy-catch; whereas existing Guile would always look for a
   catch/lazy-catch higher up the dynamic context.

   For example:

     (catch 'a
       (lambda ()
         (lazy-catch 'b
           (lambda ()
             (catch 'a
               (lambda ()
                 (throw 'b))
               inner-handler))
           (lambda (key . args)
             (throw 'a))))
       outer-handler)

   Current Guile would handle the (throw 'a) by calling outer-handler,
   and continuing with the continuation of the outer catch.  The
   proposed implementation would call inner-handler and continue with
   the continuation of the inner catch.

   This seems surprising at first, but I reckon it's inevitable if you
   are serious about executing lazy handlers truly lazily - i.e. in
   the full context of the original throw.

I think all these changes are sufficiently obscure that we could get
away with implementing them under lazy-catch.  But if we want to be
ultra-cautious we could keep lazy-catch as it is and introduce
`with-pre-unwind-handler' (or something) with the proposed semantics.

Anyone still reading?  What do you think?

       Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-02-01 23:04                             ` Neil Jerram
@ 2006-02-04  0:46                               ` Kevin Ryde
  2006-02-04 15:41                                 ` Neil Jerram
  0 siblings, 1 reply; 32+ messages in thread
From: Kevin Ryde @ 2006-02-04  0:46 UTC (permalink / raw)
  Cc: guile-devel

Neil Jerram <neil@ossau.uklinux.net> writes:
>
> The spec for catch's pre-unwind-handler would be that it can exit
> either normally or non-locally.  If it exits normally, Guile unwinds
> (dynamic context + stack) and then calls the normal (post-unwind)
> handler.  If it exits non-locally, that exit determines the
> continuation.

Hmm.  Now my head hurts.  I'm not so sure what I want any more (apart
from a reliable backtrace).

> But if we want to be ultra-cautious we could keep lazy-catch as it
> is and introduce `with-pre-unwind-handler' (or something) with the
> proposed semantics.

Better be pretty strictly compatible, it's hairy enough without
changing between guile versions.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: Backtrace and enhanced catch
  2006-02-04  0:46                               ` Kevin Ryde
@ 2006-02-04 15:41                                 ` Neil Jerram
  0 siblings, 0 replies; 32+ messages in thread
From: Neil Jerram @ 2006-02-04 15:41 UTC (permalink / raw)


Kevin Ryde <user42@zip.com.au> writes:

> Neil Jerram <neil@ossau.uklinux.net> writes:
>>
>> The spec for catch's pre-unwind-handler would be that it can exit
>> either normally or non-locally.  If it exits normally, Guile unwinds
>> (dynamic context + stack) and then calls the normal (post-unwind)
>> handler.  If it exits non-locally, that exit determines the
>> continuation.
>
> Hmm.  Now my head hurts.

:-)  Sorry about that!

Well anyway, I feel pretty confident about it all, and the code's now
in CVS.

> I'm not so sure what I want any more (apart from a reliable
> backtrace).

That's working now.

>> But if we want to be ultra-cautious we could keep lazy-catch as it
>> is and introduce `with-pre-unwind-handler' (or something) with the
>> proposed semantics.
>
> Better be pretty strictly compatible, it's hairy enough without
> changing between guile versions.

Yes, that's what I thought too, so I took the "ultra-cautious"
approach.

Regards,
        Neil



_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2006-02-04 15:41 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-12-01  0:16 gh_inexact_p error in 1.7.x Bruce Korb
2005-12-01  0:44 ` Kevin Ryde
2005-12-05  4:08   ` No way out Bruce Korb
2005-12-05  4:35     ` Bruce Korb
2005-12-07  1:31       ` Marius Vollmer
2005-12-05 22:20     ` Kevin Ryde
2005-12-06 10:58       ` Han-Wen Nienhuys
2005-12-28 15:59         ` Neil Jerram
2005-12-31 15:09           ` Han-Wen Nienhuys
2005-12-31 15:14             ` Neil Jerram
2006-01-01 19:58               ` Han-Wen Nienhuys
2006-01-02 15:42                 ` Neil Jerram
2006-01-02 18:54                   ` Neil Jerram
2006-01-04 21:13                     ` Backtrace and enhanced catch Neil Jerram
2006-01-14 12:41                       ` Neil Jerram
2006-01-22 13:47                         ` Marius Vollmer
2006-01-23 20:11                           ` Neil Jerram
2006-01-24 21:34                             ` Marius Vollmer
2006-01-16  8:38                       ` Ludovic Courtès
2006-01-18 23:08                         ` Neil Jerram
2006-01-19  9:38                           ` Ludovic Courtès
2006-01-21 11:26                             ` Neil Jerram
2006-01-26 23:29                       ` Kevin Ryde
2006-01-27 19:30                         ` Neil Jerram
2006-01-31 20:07                           ` Kevin Ryde
2006-02-01 23:04                             ` Neil Jerram
2006-02-04  0:46                               ` Kevin Ryde
2006-02-04 15:41                                 ` Neil Jerram
2005-12-07  1:07     ` No way out Marius Vollmer
2005-12-07  1:55       ` Rob Browning
2005-12-13 20:32         ` Marius Vollmer
2005-12-28 16:09       ` Neil Jerram

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).