Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

How to access (waiter-interrupt) used internally by (break) and (keyboard-interrupt-handler) from custom repl?

36 views
Skip to first unread message

Massimiliano Ghilardi

unread,
Dec 25, 2023, 1:12:10 PM12/25/23
to chez-scheme
Hello everybody,

I am implementing schemesh (https://github.com/cosmos72/schemesh), a Chez Scheme based interactive shell which offers both scheme syntax and shell syntax.

The readers/parsers are complete, and the custom repl is almost complete too.
The backend to execute commands as a shell is coming up nicely too, thanks to the C ffi :)

I am experiencing a difficulty with the custom repl I wrote:
it is started from C with
   Scall0(Stop_level_value(Sstring_to_symbol("repl")));
which bypasses the usual Chez repl (new-cafe).

For this reason, the code in (new-cafe) setting thread parameter ($interrupt) to waiter-interrupt is not executed, thus (break) and (keyboard-interrupt-handler), which internally call ($interrupt), do nothing and return immediately.

I would like (break) and (keyboard-interrupt-handler) to work in my repl as they do in the default repl (new-cafe).

How can I do that?

Some ideas coming to my mind could be:

* Is there any way to retrieve the value of waiter-interrupt ? It seems unexported.
* In alternative, is there a programmatic API to invoke (new-cafe) and instruct it to just call my custom (repl) instead of its usual behavior ?
* I guess in the worst case I could reimplement waiter-interrupt myself - it seems simple enough - but feels a hack to me.

Thanks,
Massimiliano Ghilardi

Andy Keep

unread,
Dec 26, 2023, 9:02:40 PM12/26/23
to chez-scheme
Hello Massimiliano,

I think there are a couple of options, if you'd like to use the existing waiter/new-cafe system, there are some ways to customize this, including setting the prompt, reader and evaluator, which I think should give you most of the control you need. Check out the Waiter Customization section for more details... the short version is new-cafe will allow you to specify an evaluation function to replace the normal Chez Scheme eval and the waiter-prompt-and-read parameter allows you to provide a procedure that can print the prompt and read from standard input, which will then be passed to the eval function.

Alternatively, you can use the reset-handler, exit-handler, and abort-handler parameters to control what happens when the standard $interrupt handler is invoked. Have a look at the crepl.c program in examples to make sure the Scheme system is initialized correctly first, this sets up the standard $interrupt handler, then you can build up a repl loop from there. I was toying around with this last night just to see how minimal I could build something. Something like the following is sufficient to recover from errors in the repl and return to the prompt. The default-exception-handler is already configured to set the debug-condition which controls what happens when the debug function is called, though there is some more work needed to get the continuation set correctly for inspection by the default handler. It is also possible to override the default-exception-handler with the with-exception-handler form and you can subscribe to interrupt signals with register-signal-handler and even override the default keyboard and timer interrupt handlers with the keyboard-interrupt-handler parameter and the timer-interrupt-handler parameter.

% export CHEZ_HOME=/usr/local/lib/csv9.9.9-pre-release.20/tarm64osx
% clang -o crepl crepl.c -I $CHEZ_HOME -L $CHEZ_HOME -lkernel -llz4 -lz -liconv -lncurses
% ./crepl -b $CHEZ_HOME/petite.boot -b $CHEZ_HOME/scheme.boot
* (let mini-repl ()
    (call/cc (lambda (k) (reset-handler (lambda () (printf "Last expression caused an exception.\n") (k (void))))))
    (printf "$ ")
    (let ([e (read (current-input-port))])
      (unless (eof-object? e)
        (pretty-print (eval e))
        (mini-repl))))
$ (+ 4 5)
9
$ (+ 4 'a)

Exception in +: a is not a number
Last expression caused an exception.
$ (debug)
debug> s
  Exception in +: a is not a number
debug> c
#<compound condition>                                             : s
  0. components:         (#<condition &assertion> #<condition &format> ...)
#<compound condition>                                             : r 0
(#<condition &assertion> #<condition &format> ...)                : s
  0: #<condition &assertion>
  1: #<condition &format>
  2: #<condition &who>
  3: #<condition &message>
  4: #<condition &irritants>
  5: #<condition &continuation>
(#<condition &assertion> #<condition &format> ...)                : r 5
#<condition &continuation>                                        : s
  0. k:                  #<continuation>
#<condition &continuation>                                        : r k
#<continuation>                                                   : s
  continuation:          #<system continuation in invoke>
  call code:             (eval e)
#<continuation>                                                   : d
#<system continuation in invoke>                                  : s
  continuation:          #<null continuation>
  frame and free variables:
  0: ((13194142445568 #<void> . #f))
#<system continuation in invoke>                                  : s
  continuation:          #<null continuation>
  frame and free variables:
  0: ((13194142445568 #<void> . #f))
#<system continuation in invoke>                                  : ^D

debug> ^D
#<void>
$ * ^D



Hope that helps!
Reply all
Reply to author
Forward
0 new messages