mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 20:00:19 +02:00
113 lines
3.7 KiB
Scheme
113 lines
3.7 KiB
Scheme
(define-module (lang elisp internals fset)
|
|
#:use-module (lang elisp internals evaluation)
|
|
#:use-module (lang elisp internals lambda)
|
|
#:use-module (lang elisp internals signal)
|
|
#:export (fset
|
|
fref
|
|
fref/error-if-void
|
|
elisp-apply
|
|
interactive-specification
|
|
not-subr?
|
|
elisp-export-module))
|
|
|
|
(define the-variables-module (resolve-module '(lang elisp variables)))
|
|
|
|
;; By default, Guile GC's unreachable symbols. So we need to make
|
|
;; sure they stay reachable!
|
|
(define syms '())
|
|
|
|
;; elisp-export-module, if non-#f, holds a module to which definitions
|
|
;; should be exported under their normal symbol names. This is used
|
|
;; when importing Elisp definitions into Scheme.
|
|
(define elisp-export-module (make-fluid))
|
|
|
|
;; Store the procedure, macro or alias symbol PROC in SYM's function
|
|
;; slot.
|
|
(define (fset sym proc)
|
|
(or (memq sym syms)
|
|
(set! syms (cons sym syms)))
|
|
(let ((vcell (symbol-fref sym))
|
|
(vsym #f)
|
|
(export-module (fluid-ref elisp-export-module)))
|
|
;; Playing around with variables and name properties... For the
|
|
;; reasoning behind this, see the commentary in (lang elisp
|
|
;; variables).
|
|
(cond ((procedure? proc)
|
|
;; A procedure created from Elisp will already have a name
|
|
;; property attached, with value of the form
|
|
;; <elisp-defun:NAME> or <elisp-lambda>. Any other
|
|
;; procedure coming through here must be an Elisp primitive
|
|
;; definition, so we give it a name of the form
|
|
;; <elisp-subr:NAME>.
|
|
(or (procedure-name proc)
|
|
(set-procedure-property! proc
|
|
'name
|
|
(symbol-append '<elisp-subr: sym '>)))
|
|
(set! vsym (procedure-name proc)))
|
|
((macro? proc)
|
|
;; Macros coming through here must be defmacros, as all
|
|
;; primitive special forms are handled directly by the
|
|
;; transformer.
|
|
(set-procedure-property! (macro-transformer proc)
|
|
'name
|
|
(symbol-append '<elisp-defmacro: sym '>))
|
|
(set! vsym (procedure-name (macro-transformer proc))))
|
|
(else
|
|
;; An alias symbol.
|
|
(set! vsym (symbol-append '<elisp-defalias: sym '>))))
|
|
;; This is the important bit!
|
|
(if (variable? vcell)
|
|
(variable-set! vcell proc)
|
|
(begin
|
|
(set! vcell (make-variable proc))
|
|
(symbol-fset! sym vcell)
|
|
;; Playing with names and variables again - see above.
|
|
(module-add! the-variables-module vsym vcell)
|
|
(module-export! the-variables-module (list vsym))))
|
|
;; Export variable to the export module, if non-#f.
|
|
(if (and export-module
|
|
(or (procedure? proc)
|
|
(macro? proc)))
|
|
(begin
|
|
(module-add! export-module sym vcell)
|
|
(module-export! export-module (list sym))))))
|
|
|
|
;; Retrieve the procedure or macro stored in SYM's function slot.
|
|
;; Note the asymmetry w.r.t. fset: if fref finds an alias symbol, it
|
|
;; recursively calls fref on that symbol. Returns #f if SYM's
|
|
;; function slot doesn't contain a valid definition.
|
|
(define (fref sym)
|
|
(let ((var (symbol-fref sym)))
|
|
(if (and var (variable? var))
|
|
(let ((proc (variable-ref var)))
|
|
(cond ((symbol? proc)
|
|
(fref proc))
|
|
(else
|
|
proc)))
|
|
#f)))
|
|
|
|
;; Same as fref, but signals an Elisp error if SYM's function
|
|
;; definition is void.
|
|
(define (fref/error-if-void sym)
|
|
(or (fref sym)
|
|
(signal 'void-function (list sym))))
|
|
|
|
;; Maps a procedure to its (interactive ...) spec.
|
|
(define interactive-specification (make-object-property))
|
|
|
|
;; Maps a procedure to #t if it is NOT a built-in.
|
|
(define not-subr? (make-object-property))
|
|
|
|
(define (elisp-apply function . args)
|
|
(apply apply
|
|
(cond ((symbol? function)
|
|
(fref/error-if-void function))
|
|
((procedure? function)
|
|
function)
|
|
((and (pair? function)
|
|
(eq? (car function) 'lambda))
|
|
(eval (transform-lambda/interactive function '<elisp-lambda>)
|
|
the-root-module))
|
|
(else
|
|
(signal 'invalid-function (list function))))
|
|
args))
|