]> git.donarmstrong.com Git - lilypond.git/blobdiff - guile18/lang/elisp/interface.scm
Import guile-1.8 as multiple upstream tarball component
[lilypond.git] / guile18 / lang / elisp / interface.scm
diff --git a/guile18/lang/elisp/interface.scm b/guile18/lang/elisp/interface.scm
new file mode 100644 (file)
index 0000000..1e07585
--- /dev/null
@@ -0,0 +1,128 @@
+(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))