File size: 4,885 Bytes
f65fe85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
(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))