guile.el 6.6 KB

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