Commit | Line | Data |
---|---|---|
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 | ||
22 | ;;; | |
23 | ;;; Low level interface | |
24 | ;;; | |
25 | ||
26 | (defvar guile-token "<guile>") | |
27 | ||
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 | ||
36 | (defun guile:make-adapter (command channel) | |
37 | (let* ((buff (generate-new-buffer " *guile object channel*")) | |
38 | (proc (start-process "guile-oa" buff command | |
39 | "-q" "-l" gulie-emacs-file))) | |
40 | (process-kill-without-query proc) | |
41 | (accept-process-output proc) | |
42 | (guile-process-require proc (format "(%s)\n" channel) "channel> ") | |
43 | proc)) | |
44 | ||
45 | (put 'guile-error 'error-conditions '(guile-error error)) | |
46 | (put 'guile-error 'error-message "Guile error") | |
47 | ||
48 | (defun guile:eval (string adapter) | |
49 | (let ((output (guile-process-require adapter (concat "eval " string "\n") | |
50 | "channel> "))) | |
51 | (cond | |
52 | ((string= output "") nil) | |
53 | ((string-match "^\\(\\(value\\)\\|\\(token\\)\\|\\(exception\\)\\) = " | |
54 | output) | |
55 | (cond | |
56 | ;; value | |
57 | ((match-beginning 2) | |
58 | (car (read-from-string (substring output (match-end 0))))) | |
59 | ;; token | |
60 | ((match-beginning 3) | |
61 | (cons guile-token | |
62 | (car (read-from-string (substring output (match-end 0)))))) | |
63 | ;; exception | |
64 | ((match-beginning 4) | |
65 | (signal 'guile-error | |
66 | (car (read-from-string (substring output (match-end 0)))))))) | |
67 | (t | |
68 | (error "Unsupported result" output))))) | |
69 | ||
70 | \f | |
71 | ;;; | |
72 | ;;; Guile Lisp adapter | |
73 | ;;; | |
74 | ||
75 | (defvar guile-lisp-command "guile") | |
76 | (defvar guile-lisp-adapter nil) | |
77 | ||
78 | (defvar true "#t") | |
79 | (defvar false "#f") | |
80 | ||
81 | (defun guile-lisp-adapter () | |
82 | (if (and (processp guile-lisp-adapter) | |
83 | (eq (process-status guile-lisp-adapter) 'run)) | |
84 | guile-lisp-adapter | |
85 | (setq guile-lisp-adapter | |
86 | (guile:make-adapter guile-lisp-command 'emacs-lisp-channel)))) | |
87 | ||
88 | (defun guile-lisp-convert (x) | |
89 | (cond | |
90 | ((or (eq x true) (eq x false)) x) | |
91 | ((stringp x) (prin1-to-string x)) | |
92 | ((consp x) | |
93 | (if (eq (car x) guile-token) | |
94 | (cadr x) | |
95 | (cons (guile-lisp-convert (car x)) (guile-lisp-convert (cdr x))))) | |
96 | (t x))) | |
97 | ||
98 | (defun guile-lisp-eval (exp) | |
99 | (guile:eval (format "%s" (guile-lisp-convert exp)) (guile-lisp-adapter))) | |
100 | ||
101 | ;;;###autoload | |
102 | (defmacro guile-import (name) | |
103 | `(guile-process-import ',name)) | |
104 | ||
105 | (defun guile-process-import (name) | |
106 | (eval (guile-lisp-eval `(guile-emacs-export ',name)))) | |
107 | ||
108 | ;;;###autoload | |
109 | (defmacro guile-use-modules (&rest name-list) | |
110 | `(guile-process-use-modules ',name-list)) | |
111 | ||
112 | (defun guile-process-use-modules (list) | |
113 | (unless (boundp 'guile-emacs-export-procedures) | |
114 | (guile-import guile-emacs-export-procedures)) | |
115 | (guile-lisp-eval `(use-modules ,@list)) | |
116 | (mapc (lambda (name) (eval (guile-emacs-export-procedures name))) list)) | |
117 | ||
118 | \f | |
119 | ;;; | |
120 | ;;; Process handling | |
121 | ;;; | |
122 | ||
123 | (defvar guile-process-output-start nil) | |
124 | (defvar guile-process-output-value nil) | |
125 | (defvar guile-process-output-finished nil) | |
126 | (defvar guile-process-output-separator nil) | |
127 | ||
128 | (defun guile-process-require (process string separator) | |
129 | (setq guile-process-output-value nil) | |
130 | (setq guile-process-output-finished nil) | |
131 | (setq guile-process-output-separator separator) | |
132 | (let (temp-buffer) | |
133 | (unless (process-buffer process) | |
134 | (setq temp-buffer (guile-temp-buffer)) | |
135 | (set-process-buffer process temp-buffer)) | |
136 | (with-current-buffer (process-buffer process) | |
137 | (goto-char (point-max)) | |
138 | (insert string) | |
139 | (setq guile-process-output-start (point)) | |
140 | (set-process-filter process 'guile-process-filter) | |
141 | (process-send-string process string) | |
142 | (while (not guile-process-output-finished) | |
143 | (unless (accept-process-output process 3) | |
144 | (when (> (point) guile-process-output-start) | |
145 | (display-buffer (current-buffer)) | |
146 | (error "BUG in Guile object channel!!"))))) | |
147 | (when temp-buffer | |
148 | (set-process-buffer process nil) | |
149 | (kill-buffer temp-buffer))) | |
150 | guile-process-output-value) | |
151 | ||
152 | (defun guile-process-filter (process string) | |
153 | (with-current-buffer (process-buffer process) | |
154 | (insert string) | |
155 | (forward-line -1) | |
156 | (if (< (point) guile-process-output-start) | |
157 | (goto-char guile-process-output-start)) | |
158 | (when (re-search-forward guile-process-output-separator nil 0) | |
159 | (goto-char (match-beginning 0)) | |
160 | (setq guile-process-output-value | |
161 | (buffer-substring guile-process-output-start (point))) | |
162 | (setq guile-process-output-finished t)))) | |
163 | ||
164 | (defun guile-process-kill (process) | |
165 | (set-process-filter process nil) | |
166 | (delete-process process) | |
167 | (if (process-buffer process) | |
168 | (kill-buffer (process-buffer process)))) | |
169 | ||
170 | (provide 'guile) | |
171 | ||
172 | ;;; guile.el ends here |