guile-devel-internal
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

comments on lgh


From: Josh MacDonald
Subject: comments on lgh
Date: Fri, 13 Sep 1996 22:56:51 -0700

I got a copy of lgh from Mark tonight and have some comments
for everyone.  

First I'll describe my background with scheme.  I've used STk 
quite a bit, but never embedded a scheme application in a C
program.  I'm quite familiar with the STklos object layer there,
having used it to implement a real-time interactive scheme environment
diagrammer.

Second, I'll describe the application.  I'm working with the 
GIMP developers on an extension language.

My initial attempts were to to the simplest possible incorperation
of guile into the gimp -- run a guile interpreter while running
the gimp.  To do this I'd like to attach the terminal to an interpreter,
but since there's other windows to pay attention to, reads need to
be non-blocking.  This causes problems, as far as I can tell.  
So I can't see any support for this type of read in guile, and I
construct my own REPL that makes a soft-port out of input as it
arrives, catches an exception when a read occurs and no input is
available, and re-evaluate everything in the buffer when more input
is available.  This is obviously susceptable to errors and odd behaviour,
but its the best I could come up with easily.  So I write the following
(this may still have errors, I never really embedded it and tested it
much.  this is proof-of-concept, it can also be more efficient):

(define (gimp-send-input string)
  (if (> (length *gimp-input-buffer*) 0)
      (set! *gimp-input-buffer* (string-append (substring *gimp-input-buffer*
                                                          *gimp-input-position*
                                                          (length 
*gimp-input-buffer*))
                                               string))
      (set! *gimp-input-buffer* string))
  (catch #t gimp-send-thunk gimp-send-error-handler))

(define (gimp-send-thunk)
  (let loop ()
    (set! *gimp-saved-input-position* *gimp-input-position*)
    (cond ((>= *gimp-input-position* (length *gimp-input-buffer*))
           (set! *gimp-input-position* 0)
           (set! *gimp-input-buffer* ""))
          ((catch #f gimp-repl gimp-restore-input)
           (loop))
          (else #f))))

(define gimp-send-error-handler (lambda args
  (display ";;; An error occured.\n")
  (display args)
  (display "\n")
  (force-output)))

(define (gimp-repl jump)
  (set! *gimp-jump-buffer* jump)
  (display (eval (read *gimp-input-port*)))
  (display "\ngimp> ")
  (force-output)
  #t)

(define gimp-restore-input
  (lambda args
    (set! *gimp-input-position* *gimp-saved-input-position*)
    #f))

(define (gimp-read-char)
  (if (< *gimp-input-position* (length *gimp-input-buffer*))
      (let ((index *gimp-input-position*))
        (set! *gimp-input-position* (+ *gimp-input-position* 1))
        (string-ref *gimp-input-buffer* index))
      (throw *gimp-jump-buffer*)))

(define (gimp-close-input) '())

(define *gimp-input-buffer* "")

(define *gimp-input-position* 0)

(define *gimp-input-port* (make-soft-port
                           (vector #f #f #f
                                   gimp-read-char
                                   gimp-close-input)
                           "r"))

(define *gimp-jump-buffer* '())

(define *gimp-saved-input-position* '())

That sort of gave me what I wanted out of the scheme/application 
communication, but its a lot more work that I'd like to see for this
type of problem.  Its also not very helpful if I want to have a 
scheme interpreter on the terminal and at the same time, possibly
have other interpreters doing other processing.  It would be nice
to have an interface something like:

struct scm_interp;

scm_interp *make_interp();
void free_interp(*scm_interp);

SCM scm_interp_call(scm_interp* interp,
                    const char* eval_me,
                    int eval_me_len,
                    int* consumed);

where the scm_interp object saves its (read) state.  the return value
of scm_interp_call is the result of evaluating the string, or SCM_NOEXPR
or some such constant if (read) has not completed on the byte-stream yet.
That solves the non-blocking problem, as far as I can tell.

As to lgh, its no-where near useful without being able to get return
values and call scheme functions from C.  So lets say I want to use
the code I wrote above.  The entry-point is gimp-send-input, and I
have a C-string I want to send.  So I'd like to be able to initialize
my application by setting some SCM variable in my program to 
eval("gimp-send-input") and then call apply with it and the
appropriately converted string.  I can do neither the eval (and get its
return value) nor apply functions, since I can't write a useful interpreter
(how, given the current lgh functionality, would you know when to print
another prompt, you have to delegate this responsibility to the scheme
REPL, but for complicated applications you'll want to write the REPL in
C so that you can do other things at the same time.)

Are the interfaces to these lower-level functions I'd need to do my
own apply and eval from C documented anywhere?  It seems like only the
Scheme interface is documented, not the C interface.

Am I missing a more-correct way to accomplish the above things?

-josh




reply via email to

[Prev in Thread] Current Thread [Next in Thread]