1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 03:40:34 +02:00
guile/emacs/guile.el
2005-05-23 19:57:22 +00:00

215 lines
6.6 KiB
EmacsLisp
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; guile.el --- Emacs Guile interface
;; Copyright (C) 2001 Keisuke Nishida <kxn30@po.cwru.edu>
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
(require 'cl)
;;;
;;; Low level interface
;;;
(defvar guile-emacs-file
(catch 'return
(mapc (lambda (dir)
(let ((file (expand-file-name "guile-emacs.scm" dir)))
(if (file-exists-p file) (throw 'return file))))
load-path)
(error "Cannot find guile-emacs.scm")))
(defvar guile-channel-file
(catch 'return
(mapc (lambda (dir)
(let ((file (expand-file-name "channel.scm" dir)))
(if (file-exists-p file) (throw 'return file))))
load-path)
(error "Cannot find channel.scm")))
(defvar guile-libs
(nconc (if guile-channel-file (list "-l" guile-channel-file) '())
(list "-l" guile-emacs-file)))
;;;###autoload
(defun guile:make-adapter (command channel)
(let* ((buff (generate-new-buffer " *guile object channel*"))
(libs (if guile-channel-file (list "-l" guile-channel-file) nil))
(proc (apply 'start-process "guile-oa" buff command "-q" guile-libs)))
(process-kill-without-query proc)
(accept-process-output proc)
(guile-process-require proc (format "(%s)\n" channel) "channel> ")
proc))
(put 'guile-error 'error-conditions '(guile-error error))
(put 'guile-error 'error-message "Guile error")
(defvar guile-token-tag "<guile>")
(defun guile-tokenp (x) (and (consp x) (eq (car x) guile-token-tag)))
;;;###autoload
(defun guile:eval (string adapter)
(condition-case error
(let ((output (guile-process-require adapter (concat "eval " string "\n")
"channel> ")))
(cond
((string= output "") nil)
((string-match "^\\(\\(value\\)\\|\\(token\\)\\|\\(exception\\)\\) = "
output)
(cond
;; value
((match-beginning 2)
(car (read-from-string (substring output (match-end 0)))))
;; token
((match-beginning 3)
(cons guile-token-tag
(car (read-from-string (substring output (match-end 0))))))
;; exception
((match-beginning 4)
(signal 'guile-error
(car (read-from-string (substring output (match-end 0))))))))
(t
(error "Unsupported result" output))))
(quit
(signal-process (process-id adapter) 'SIGINT)
(signal 'quit nil))))
;;;
;;; Guile Lisp adapter
;;;
(defvar guile-lisp-command "guile")
(defvar guile-lisp-adapter nil)
(defvar true "#t")
(defvar false "#f")
(unless (boundp 'keywordp)
(defun keywordp (x) (and (symbolp x) (eq (aref (symbol-name x) 0) ?:))))
(defun guile-lisp-adapter ()
(if (and (processp guile-lisp-adapter)
(eq (process-status guile-lisp-adapter) 'run))
guile-lisp-adapter
(setq guile-lisp-adapter
(guile:make-adapter guile-lisp-command 'emacs-lisp-channel))))
(defun guile-lisp-convert (x)
(cond
((or (eq x true) (eq x false)) x)
((null x) "'()")
((keywordp x) (concat "#" (prin1-to-string x)))
((stringp x) (prin1-to-string x))
((guile-tokenp x) (cadr x))
((consp x)
(if (null (cdr x))
(list (guile-lisp-convert (car x)))
(cons (guile-lisp-convert (car x)) (guile-lisp-convert (cdr x)))))
(t x)))
;;;###autoload
(defun guile-lisp-eval (form)
(guile:eval (format "%s" (guile-lisp-convert form)) (guile-lisp-adapter)))
(defun guile-lisp-flat-eval (&rest form)
(let ((args (mapcar (lambda (x)
(if (guile-tokenp x) (cadr x) (list 'quote x)))
(cdr form))))
(guile-lisp-eval (cons (car form) args))))
;;;###autoload
(defmacro guile-import (name &optional new-name &rest opts)
`(guile-process-import ',name ',new-name ',opts))
(defun guile-process-import (name new-name opts)
(let ((real (or new-name name))
(docs (if (memq :with-docs opts) true false)))
(eval (guile-lisp-eval `(guile-emacs-export ',name ',real ,docs)))))
;;;###autoload
(defmacro guile-use-module (name)
`(guile-lisp-eval '(use-modules ,name)))
;;;###autoload
(defmacro guile-import-module (name &rest opts)
`(guile-process-import-module ',name ',opts))
(defun guile-process-import-module (name opts)
(unless (boundp 'guile-emacs-export-procedures)
(guile-import guile-emacs-export-procedures))
(let ((docs (if (memq :with-docs opts) true false)))
(guile-lisp-eval `(use-modules ,name))
(eval (guile-emacs-export-procedures name docs))
name))
;;;
;;; Process handling
;;;
(defvar guile-process-output-start nil)
(defvar guile-process-output-value nil)
(defvar guile-process-output-finished nil)
(defvar guile-process-output-separator nil)
(defun guile-process-require (process string separator)
(setq guile-process-output-value nil)
(setq guile-process-output-finished nil)
(setq guile-process-output-separator separator)
(let (temp-buffer)
(unless (process-buffer process)
(setq temp-buffer (guile-temp-buffer))
(set-process-buffer process temp-buffer))
(with-current-buffer (process-buffer process)
(goto-char (point-max))
(insert string)
(setq guile-process-output-start (point))
(set-process-filter process 'guile-process-filter)
(process-send-string process string)
(while (not guile-process-output-finished)
(unless (accept-process-output process 3)
(when (> (point) guile-process-output-start)
(display-buffer (current-buffer))
(error "BUG in Guile object channel!!")))))
(when temp-buffer
(set-process-buffer process nil)
(kill-buffer temp-buffer)))
guile-process-output-value)
(defun guile-process-filter (process string)
(with-current-buffer (process-buffer process)
(insert string)
(forward-line -1)
(if (< (point) guile-process-output-start)
(goto-char guile-process-output-start))
(when (re-search-forward guile-process-output-separator nil 0)
(goto-char (match-beginning 0))
(setq guile-process-output-value
(buffer-substring guile-process-output-start (point)))
(setq guile-process-output-finished t))))
(defun guile-process-kill (process)
(set-process-filter process nil)
(delete-process process)
(if (process-buffer process)
(kill-buffer (process-buffer process))))
(provide 'guile)
;;; guile.el ends here