Spaces:
Sleeping
Sleeping
(define-module (lang elisp interface) | |
#:use-module (lang elisp internals evaluation) | |
#:use-module (lang elisp internals fset) | |
#:use-module ((lang elisp internals load) #:select ((load . elisp:load))) | |
#:use-module ((lang elisp transform) #:select (transformer)) | |
#:export (eval-elisp | |
translate-elisp | |
elisp-function | |
elisp-variable | |
load-elisp-file | |
load-elisp-library | |
use-elisp-file | |
use-elisp-library | |
export-to-elisp | |
load-emacs)) | |
;;; This file holds my ideas for the mechanisms that would be useful | |
;;; to exchange definitions between Scheme and Elisp. | |
(define (eval-elisp x) | |
"Evaluate the Elisp expression @var{x}." | |
(eval x the-elisp-module)) | |
(define (translate-elisp x) | |
"Translate the Elisp expression @var{x} to equivalent Scheme code." | |
(transformer x)) | |
(define (elisp-function sym) | |
"Return the procedure or macro that implements @var{sym} in Elisp. | |
If @var{sym} has no Elisp function definition, return @code{#f}." | |
(fref sym)) | |
(define (elisp-variable sym) | |
"Return the variable that implements @var{sym} in Elisp. | |
If @var{sym} has no Elisp variable definition, return @code{#f}." | |
(module-variable the-elisp-module sym)) | |
(define (load-elisp-file file-name) | |
"Load @var{file-name} into the Elisp environment. | |
@var{file-name} is assumed to name a file containing Elisp code." | |
;; This is the same as Elisp's `load-file', so use that if it is | |
;; available, otherwise duplicate the definition of `load-file' from | |
;; files.el. | |
(let ((load-file (elisp-function 'load-file))) | |
(if load-file | |
(load-file file-name) | |
(elisp:load file-name #f #f #t)))) | |
(define (load-elisp-library library) | |
"Load library @var{library} into the Elisp environment. | |
@var{library} should name an Elisp code library that can be found in | |
one of the directories of @code{load-path}." | |
;; This is the same as Elisp's `load-file', so use that if it is | |
;; available, otherwise duplicate the definition of `load-file' from | |
;; files.el. | |
(let ((load-library (elisp-function 'load-library))) | |
(if load-library | |
(load-library library) | |
(elisp:load library)))) | |
(define export-module-name | |
(let ((counter 0)) | |
(lambda () | |
(set! counter (+ counter 1)) | |
(list 'lang 'elisp | |
(string->symbol (string-append "imports:" | |
(number->string counter))))))) | |
(define-macro (use-elisp-file file-name . imports) | |
"Load Elisp code file @var{file-name} and import its definitions | |
into the current Scheme module. If any @var{imports} are specified, | |
they are interpreted as selection and renaming specifiers as per | |
@code{use-modules}." | |
(let ((export-module-name (export-module-name))) | |
`(begin | |
(fluid-set! ,elisp-export-module (resolve-module ',export-module-name)) | |
(beautify-user-module! (resolve-module ',export-module-name)) | |
(load-elisp-file ,file-name) | |
(use-modules (,export-module-name ,@imports)) | |
(fluid-set! ,elisp-export-module #f)))) | |
(define-macro (use-elisp-library library . imports) | |
"Load Elisp library @var{library} and import its definitions into | |
the current Scheme module. If any @var{imports} are specified, they | |
are interpreted as selection and renaming specifiers as per | |
@code{use-modules}." | |
(let ((export-module-name (export-module-name))) | |
`(begin | |
(fluid-set! ,elisp-export-module (resolve-module ',export-module-name)) | |
(beautify-user-module! (resolve-module ',export-module-name)) | |
(load-elisp-library ,library) | |
(use-modules (,export-module-name ,@imports)) | |
(fluid-set! ,elisp-export-module #f)))) | |
(define (export-to-elisp . defs) | |
"Export procedures and variables specified by @var{defs} to Elisp. | |
Each @var{def} is either an object, in which case that object must be | |
a named procedure or macro and is exported to Elisp under its Scheme | |
name; or a symbol, in which case the variable named by that symbol is | |
exported under its Scheme name; or a pair @var{(obj . name)}, in which | |
case @var{obj} must be a procedure, macro or symbol as already | |
described and @var{name} specifies the name under which that object is | |
exported to Elisp." | |
(for-each (lambda (def) | |
(let ((obj (if (pair? def) (car def) def)) | |
(name (if (pair? def) (cdr def) #f))) | |
(cond ((procedure? obj) | |
(or name | |
(set! name (procedure-name obj))) | |
(if name | |
(fset name obj) | |
(error "No procedure name specified or deducible:" obj))) | |
((macro? obj) | |
(or name | |
(set! name (macro-name obj))) | |
(if name | |
(fset name obj) | |
(error "No macro name specified or deducible:" obj))) | |
((symbol? obj) | |
(or name | |
(set! name obj)) | |
(module-add! the-elisp-module name | |
(module-ref (current-module) obj))) | |
(else | |
(error "Can't export this kind of object to Elisp:" obj))))) | |
defs)) | |
(define load-emacs (elisp-function 'load-emacs)) | |