* Explain GH deprecation & plan for scm documentation.
[bpt/guile.git] / emacs / guile.el
CommitLineData
2d857fb1
KN
1;;; guile.el --- Emacs Guile interface
2
3;; Copyright (C) 2001 Keisuke Nishida <kxn30@po.cwru.edu>
4
5;; GNU Emacs is free software; you can redistribute it and/or modify
6;; it under the terms of the GNU General Public License as published by
7;; the Free Software Foundation; either version 2, or (at your option)
8;; any later version.
9
10;; GNU Emacs is distributed in the hope that it will be useful,
11;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13;; GNU General Public License for more details.
14
15;; You should have received a copy of the GNU General Public License
16;; along with GNU Emacs; see the file COPYING. If not, write to the
17;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18;; Boston, MA 02111-1307, USA.
19
20;;; Code:
21
b77e2f28
KN
22(require 'cl)
23
2d857fb1
KN
24;;;
25;;; Low level interface
26;;;
27
2d857fb1
KN
28(defvar gulie-emacs-file
29 (catch 'return
30 (mapc (lambda (dir)
31 (let ((file (expand-file-name "guile-emacs.scm" dir)))
32 (if (file-exists-p file) (throw 'return file))))
33 load-path)
34 (error "Cannot find guile-emacs.scm")))
35
9ab0d788
KN
36(defvar gulie-channel-file
37 (catch 'return
38 (mapc (lambda (dir)
39 (let ((file (expand-file-name "channel.scm" dir)))
40 (if (file-exists-p file) (throw 'return file))))
41 load-path)))
42
43(defvar guile-libs
44 (nconc (if gulie-channel-file (list "-l" gulie-channel-file) '())
45 (list "-l" gulie-emacs-file)))
46
47;;;###autoload
2d857fb1
KN
48(defun guile:make-adapter (command channel)
49 (let* ((buff (generate-new-buffer " *guile object channel*"))
9ab0d788
KN
50 (libs (if gulie-channel-file (list "-l" gulie-channel-file) nil))
51 (proc (apply 'start-process "guile-oa" buff command "-q" guile-libs)))
2d857fb1
KN
52 (process-kill-without-query proc)
53 (accept-process-output proc)
54 (guile-process-require proc (format "(%s)\n" channel) "channel> ")
55 proc))
56
57(put 'guile-error 'error-conditions '(guile-error error))
58(put 'guile-error 'error-message "Guile error")
59
37052e60
KN
60(defvar guile-token-tag "<guile>")
61
62(defun guile-tokenp (x) (and (consp x) (eq (car x) guile-token-tag)))
63
9ab0d788 64;;;###autoload
2d857fb1 65(defun guile:eval (string adapter)
19a96c8a
KN
66 (condition-case error
67 (let ((output (guile-process-require adapter (concat "eval " string "\n")
68 "channel> ")))
69 (cond
70 ((string= output "") nil)
71 ((string-match "^\\(\\(value\\)\\|\\(token\\)\\|\\(exception\\)\\) = "
72 output)
73 (cond
74 ;; value
75 ((match-beginning 2)
76 (car (read-from-string (substring output (match-end 0)))))
77 ;; token
78 ((match-beginning 3)
79 (cons guile-token-tag
80 (car (read-from-string (substring output (match-end 0))))))
81 ;; exception
82 ((match-beginning 4)
83 (signal 'guile-error
84 (car (read-from-string (substring output (match-end 0))))))))
85 (t
86 (error "Unsupported result" output))))
87 (quit
88 (signal-process (process-id adapter) 'SIGINT)
89 (signal 'quit nil))))
2d857fb1
KN
90
91\f
92;;;
93;;; Guile Lisp adapter
94;;;
95
96(defvar guile-lisp-command "guile")
97(defvar guile-lisp-adapter nil)
98
99(defvar true "#t")
100(defvar false "#f")
101
19a96c8a
KN
102(unless (boundp 'keywordp)
103 (defun keywordp (x) (and (symbolp x) (eq (aref (symbol-name x) 0) ?:))))
104
2d857fb1
KN
105(defun guile-lisp-adapter ()
106 (if (and (processp guile-lisp-adapter)
107 (eq (process-status guile-lisp-adapter) 'run))
108 guile-lisp-adapter
109 (setq guile-lisp-adapter
110 (guile:make-adapter guile-lisp-command 'emacs-lisp-channel))))
111
112(defun guile-lisp-convert (x)
113 (cond
114 ((or (eq x true) (eq x false)) x)
37052e60 115 ((null x) "'()")
9ab0d788 116 ((keywordp x) (concat "#" (prin1-to-string x)))
2d857fb1 117 ((stringp x) (prin1-to-string x))
37052e60 118 ((guile-tokenp x) (cadr x))
2d857fb1 119 ((consp x)
37052e60
KN
120 (if (null (cdr x))
121 (list (guile-lisp-convert (car x)))
2d857fb1
KN
122 (cons (guile-lisp-convert (car x)) (guile-lisp-convert (cdr x)))))
123 (t x)))
124
9ab0d788
KN
125;;;###autoload
126(defun guile-lisp-eval (form)
127 (guile:eval (format "%s" (guile-lisp-convert form)) (guile-lisp-adapter)))
128
129(defun guile-lisp-flat-eval (&rest form)
130 (let ((args (mapcar (lambda (x)
131 (if (guile-tokenp x) (cadr x) (list 'quote x)))
132 (cdr form))))
133 (guile-lisp-eval (cons (car form) args))))
2d857fb1
KN
134
135;;;###autoload
9ab0d788
KN
136(defmacro guile-import (name &optional new-name &rest opts)
137 `(guile-process-import ',name ',new-name ',opts))
2d857fb1 138
9ab0d788
KN
139(defun guile-process-import (name new-name opts)
140 (let ((real (or new-name name))
141 (docs (if (memq :with-docs opts) true false)))
142 (eval (guile-lisp-eval `(guile-emacs-export ',name ',real ,docs)))))
2d857fb1 143
19a96c8a
KN
144;;;###autoload
145(defmacro guile-use-module (name)
146 `(guile-lisp-eval '(use-modules ,name)))
147
2d857fb1 148;;;###autoload
9ab0d788 149(defmacro guile-import-module (name &rest opts)
19a96c8a 150 `(guile-process-import-module ',name ',opts))
2d857fb1 151
19a96c8a 152(defun guile-process-import-module (name opts)
2d857fb1
KN
153 (unless (boundp 'guile-emacs-export-procedures)
154 (guile-import guile-emacs-export-procedures))
9ab0d788
KN
155 (let ((docs (if (memq :with-docs opts) true false)))
156 (guile-lisp-eval `(use-modules ,name))
157 (eval (guile-emacs-export-procedures name docs))
158 name))
2d857fb1
KN
159
160\f
161;;;
162;;; Process handling
163;;;
164
165(defvar guile-process-output-start nil)
166(defvar guile-process-output-value nil)
167(defvar guile-process-output-finished nil)
168(defvar guile-process-output-separator nil)
169
170(defun guile-process-require (process string separator)
171 (setq guile-process-output-value nil)
172 (setq guile-process-output-finished nil)
173 (setq guile-process-output-separator separator)
174 (let (temp-buffer)
175 (unless (process-buffer process)
176 (setq temp-buffer (guile-temp-buffer))
177 (set-process-buffer process temp-buffer))
178 (with-current-buffer (process-buffer process)
179 (goto-char (point-max))
180 (insert string)
181 (setq guile-process-output-start (point))
182 (set-process-filter process 'guile-process-filter)
183 (process-send-string process string)
184 (while (not guile-process-output-finished)
185 (unless (accept-process-output process 3)
186 (when (> (point) guile-process-output-start)
187 (display-buffer (current-buffer))
188 (error "BUG in Guile object channel!!")))))
189 (when temp-buffer
190 (set-process-buffer process nil)
191 (kill-buffer temp-buffer)))
192 guile-process-output-value)
193
194(defun guile-process-filter (process string)
195 (with-current-buffer (process-buffer process)
196 (insert string)
197 (forward-line -1)
198 (if (< (point) guile-process-output-start)
199 (goto-char guile-process-output-start))
200 (when (re-search-forward guile-process-output-separator nil 0)
201 (goto-char (match-beginning 0))
202 (setq guile-process-output-value
203 (buffer-substring guile-process-output-start (point)))
204 (setq guile-process-output-finished t))))
205
206(defun guile-process-kill (process)
207 (set-process-filter process nil)
208 (delete-process process)
209 (if (process-buffer process)
210 (kill-buffer (process-buffer process))))
211
212(provide 'guile)
213
214;;; guile.el ends here