1 |
|
(define-module (lang elisp interface) |
2 |
|
#:use-module (lang elisp internals evaluation) |
3 |
|
#:use-module (lang elisp internals fset) |
4 |
|
#:use-module ((lang elisp internals load) #:select ((load . elisp:load))) |
5 |
|
#:export (eval-elisp |
6 |
|
elisp-function |
7 |
|
elisp-variable |
8 |
|
load-elisp-file |
9 |
|
load-elisp-library |
10 |
|
use-elisp-file |
11 |
|
use-elisp-library |
12 |
|
export-to-elisp |
13 |
|
load-emacs)) |
14 |
|
|
15 |
|
;;; This file holds my ideas for the mechanisms that would be useful |
16 |
|
;;; to exchange definitions between Scheme and Elisp. |
17 |
|
|
18 |
|
(define (eval-elisp x) |
19 |
|
"Evaluate the Elisp expression @var{x}." |
20 |
|
(eval x the-elisp-module)) |
21 |
|
|
22 |
|
(define (elisp-function sym) |
23 |
|
"Return the procedure or macro that implements @var{sym} in Elisp. |
24 |
|
If @var{sym} has no Elisp function definition, return @code{#f}." |
25 |
|
(fref sym)) |
26 |
|
|
27 |
|
(define (elisp-variable sym) |
28 |
|
"Return the variable that implements @var{sym} in Elisp. |
29 |
|
If @var{sym} has no Elisp variable definition, return @code{#f}." |
30 |
|
(module-variable the-elisp-module sym)) |
31 |
|
|
32 |
|
(define (load-elisp-file file-name) |
33 |
|
"Load @var{file-name} into the Elisp environment. |
34 |
|
@var{file-name} is assumed to name a file containing Elisp code." |
35 |
|
;; This is the same as Elisp's `load-file', so use that if it is |
36 |
|
;; available, otherwise duplicate the definition of `load-file' from |
37 |
|
;; files.el. |
38 |
|
(let ((load-file (elisp-function 'load-file))) |
39 |
|
(if load-file |
40 |
|
(load-file file-name) |
41 |
|
(elisp:load file-name #f #f #t)))) |
42 |
|
|
43 |
|
(define (load-elisp-library library) |
44 |
|
"Load library @var{library} into the Elisp environment. |
45 |
|
@var{library} should name an Elisp code library that can be found in |
46 |
|
one of the directories of @code{load-path}." |
47 |
|
;; This is the same as Elisp's `load-file', so use that if it is |
48 |
|
;; available, otherwise duplicate the definition of `load-file' from |
49 |
|
;; files.el. |
50 |
|
(let ((load-library (elisp-function 'load-library))) |
51 |
|
(if load-library |
52 |
|
(load-library library) |
53 |
|
(elisp:load library)))) |
54 |
|
|
55 |
|
(define export-module-name |
56 |
|
(let ((counter 0)) |
57 |
|
(lambda () |
58 |
|
(set! counter (+ counter 1)) |
59 |
|
(list 'lang 'elisp |
60 |
|
(string->symbol (string-append "imports:" |
61 |
|
(number->string counter))))))) |
62 |
|
|
63 |
|
(define-macro (use-elisp-file file-name . imports) |
64 |
|
"Load Elisp code file @var{file-name} and import its definitions |
65 |
|
into the current Scheme module. If any @var{imports} are specified, |
66 |
|
they are interpreted as selection and renaming specifiers as per |
67 |
|
@code{use-modules}." |
68 |
|
(let ((export-module-name (export-module-name))) |
69 |
|
`(begin |
70 |
|
(fluid-set! ,elisp-export-module (resolve-module ',export-module-name)) |
71 |
|
(beautify-user-module! (resolve-module ',export-module-name)) |
72 |
|
(load-elisp-file ,file-name) |
73 |
|
(use-modules (,export-module-name ,@imports)) |
74 |
|
(fluid-set! ,elisp-export-module #f)))) |
75 |
|
|
76 |
|
(define-macro (use-elisp-library library . imports) |
77 |
|
"Load Elisp library @var{library} and import its definitions into |
78 |
|
the current Scheme module. If any @var{imports} are specified, they |
79 |
|
are interpreted as selection and renaming specifiers as per |
80 |
|
@code{use-modules}." |
81 |
|
(let ((export-module-name (export-module-name))) |
82 |
|
`(begin |
83 |
|
(fluid-set! ,elisp-export-module (resolve-module ',export-module-name)) |
84 |
|
(beautify-user-module! (resolve-module ',export-module-name)) |
85 |
|
(load-elisp-library ,library) |
86 |
|
(use-modules (,export-module-name ,@imports)) |
87 |
|
(fluid-set! ,elisp-export-module #f)))) |
88 |
|
|
89 |
|
(define (export-to-elisp . defs) |
90 |
|
"Export procedures and variables specified by @var{defs} to Elisp. |
91 |
|
Each @var{def} is either an object, in which case that object must be |
92 |
|
a named procedure or macro and is exported to Elisp under its Scheme |
93 |
|
name; or a symbol, in which case the variable named by that symbol is |
94 |
|
exported under its Scheme name; or a pair @var{(obj . name)}, in which |
95 |
|
case @var{obj} must be a procedure, macro or symbol as already |
96 |
|
described and @var{name} specifies the name under which that object is |
97 |
|
exported to Elisp." |
98 |
|
(for-each (lambda (def) |
99 |
|
(let ((obj (if (pair? def) (car def) def)) |
100 |
|
(name (if (pair? def) (cdr def) #f))) |
101 |
|
(cond ((procedure? obj) |
102 |
|
(or name |
103 |
|
(set! name (procedure-name obj))) |
104 |
|
(if name |
105 |
|
(fset name obj) |
106 |
|
(error "No procedure name specified or deducible:" obj))) |
107 |
|
((macro? obj) |
108 |
|
(or name |
109 |
|
(set! name (macro-name obj))) |
110 |
|
(if name |
111 |
|
(fset name obj) |
112 |
|
(error "No macro name specified or deducible:" obj))) |
113 |
|
((symbol? obj) |
114 |
|
(or name |
115 |
|
(set! name symbol)) |
116 |
|
(module-add! the-elisp-module name |
117 |
|
(module-ref (current-module) obj))) |
118 |
|
(else |
119 |
|
(error "Can't export this kind of object to Elisp:" obj))))) |
120 |
|
defs)) |
121 |
|
|
122 |
|
(define load-emacs (elisp-function 'load-emacs)) |