[Top][All Lists]
[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))))))))
- rfc: `process-define-module': function -> macro ?,
thi <=