(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))