guile.el 6.7 KB

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