guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

rfc: `process-define-module': function -> macro ?


From: thi
Subject: rfc: `process-define-module': function -> macro ?
Date: Thu, 17 May 2001 02:24:39 -0700

i've just been investigating how to clean up `resolve-interface' so that
it's not necessary to do `eval'.  below is a function and macro pair
that do the job, although there is still `local-eval'.  as far as i can
tell (please correct me if i'm wrong), this stems from the fact that
`process-define-module' (which calls `resolve-interface') is a procedure
and not a macro.

this was fine until now because all elements to be processed used to be
symbols (some with specially-handled `:' prefix) which simply evaluate
to themselves.  however, w/ the introduction of the `:rename RENAMER'
clause to `resolve-interface', that simplicity no longer holds, and the
lack of read-time selective evaluation in `process-define-module' forces
weird stuff like below.

i notice that `process-define-module' is wrapped by the thin macro
`define-module' anyway, so what i would like to do is to move more of
`process-define-module' into the macro side of things (ideally, all, but
minimally, the bits that call `resolve-interface').  is that wise?  are
there any dire consequences i've missed?

anyway, please have a look at the horrific code below (you can drop it
cleanly into boot-9.scm -- e.g., "make check" passes) and advise me on
what to do.  the more i think about it, the more the current `(eval
RENAMER (current-module))' looks good to me.  it does exactly what i
want it to do, using abstractions that are user-friendly ("RENAMER
should be a proc visible in the current module" -- not tricky at all).
maybe this is a truly legitimate use of `eval' that we can just leave
alone?

thi


____________________________________________________________
(define (%resolve-interface name bindings-map rename)
  ;; name: list of symbols
  ;; bindings-map: list of symbol conses, or #f
  ;; rename: procedure that takes a symbol and returns a symbol, or #f
  (let* ((module (resolve-module name))
         (public-i (and module (module-public-interface module)))
         (simple? (and (not bindings-map) (not rename))))
    (and (or (not module) (not public-i))
         (error "no code for module" name))
    (if simple?
        public-i
        (let ((custom-i (make-module 31)))
          (set-module-kind! custom-i 'interface)
          (for-each (lambda (bspec)
                      (let ((orig (car bspec))
                            (seen (cdr bspec)))
                        (module-add! custom-i (rename seen)
                                     (or (module-local-variable module orig)
                                         (error
                                          ;; fixme: format manually for now
                                          (simple-format
                                           #f "no binding `~A' in module ~A"
                                           orig name))))))
                    (or bindings-map
                        (module-map (lambda (sym var) (cons sym sym))
                                    public-i)))
          custom-i))))

;; Return a module interface made from SPEC.
;; SPEC can be a list of symbols, in which case it names a module
;; whose public interface is found and returned.
;;
;; SPEC can also be of the form:
;;  (MODULE-NAME [:select SELECTION] [:rename RENAMER])
;; in which case a partial interface is newly created and returned.
;; MODULE-NAME is a list of symbols, as above; SELECTION is a list of
;; binding-specs to be imported; and RENAMER is a procedure that takes a
;; symbol and returns its new name.  A binding-spec is either a symbol or a
;; pair of symbols (ORIG . SEEN), where ORIG is the name in the used module
;; and SEEN is the name in the using module.  Note that SEEN is also passed
;; through RENAMER.
;;
;; The `:select' and `:rename' clauses are optional.  If both are omitted, the
;; returned interface has no bindings.  If the `:select' clause is omitted,
;; RENAMER operates on the used module's public interface.
;;
;; Signal "no code for module" error if module name is not resolvable or its
;; public interface is not available.  Signal "no binding" error if selected
;; binding does not exist in the used module.
;;
(define resolve-interface
  (procedure->macro
   (lambda (exp env)
     (let* ((spec (local-eval (cadr exp) env))          ;; <-- hmmmmmmmm
            (simple? (not (pair? (car spec))))
            (name (if simple? spec (car spec))))
       `(%resolve-interface
         ',name
         ',(cond ((memq ':select spec)
                  => (lambda (rest)
                       (map (lambda (x) (if (pair? x) x (cons x x)))
                            (cadr rest))))
                 (else #f))
         ,(cond ((memq ':rename spec) => cadr)
                (else (if simple? #f identity))))))))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]