(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 ;; or . Any other ;; procedure coming through here must be an Elisp primitive ;; definition, so we give it a name of the form ;; . (or (procedure-name proc) (set-procedure-property! proc 'name (symbol-append '))) (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 ')) (set! vsym (procedure-name (macro-transformer proc)))) (else ;; An alias symbol. (set! vsym (symbol-append ')))) ;; 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 ') the-root-module)) (else (signal 'invalid-function (list function)))) args))