123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- ;;; Ported from Scheme 48 1.9. See file COPYING for notices and license.
- ;;;
- ;;; Port Author: Andrew Whatson
- ;;;
- ;;; Original Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Will Noble
- ;;;
- ;;; scheme48-1.9.2/scheme/bcomp/transform.scm
- ;;;
- ;;; Transforms
- ;;;
- ;;; A transform represents a source-to-source rewrite rule: either a
- ;;; macro or an in-line procedure.
- (define-module (prescheme bcomp transform)
- #:use-module (srfi srfi-9)
- #:use-module (prescheme scheme48)
- #:use-module (prescheme record-discloser)
- #:use-module (prescheme bcomp binding)
- #:use-module (prescheme bcomp cenv)
- #:use-module (prescheme bcomp mtype)
- #:use-module (prescheme bcomp name)
- #:use-module (prescheme bcomp transform4)
- #:export (make-transform/macro
- make-transform/inline
- maybe-apply-macro-transform
- apply-inline-transform
- transform?
- transform-kind
- transform-type
- transform-env ;; These are used to reify transforms.
- transform-aux-names
- transform-source
- transform-id
- make-transform))
- (define-record-type :transform
- (really-make-transform kind xformer env type aux-names source id)
- transform?
- ;; macro or inline
- (kind transform-kind)
- (xformer transform-procedure)
- (env transform-env)
- (type transform-type)
- (aux-names transform-aux-names) ;;for reification
- (source transform-source) ;;for reification
- (id transform-id))
- (define (make-transform/macro thing env type source id)
- (let ((type (if (or (pair? type)
- (symbol? type))
- (sexp->type type #t)
- type)))
- (call-with-values
- (lambda ()
- (if (pair? thing)
- (values (car thing) (cdr thing))
- (values thing #f)))
- (lambda (transformer aux-names)
- ;; The usual old-style transformers take 3 args: exp rename compare.
- ;; However, syntax-rules-generated transformers need a 4th arg, name?.
- ;; Distinguish between the two kinds.
- (let ((proc
- (cond
- ((explicit-renaming-transformer/4? transformer)
- (explicit-renaming-transformer/4-proc transformer))
- (else ;; standard explicit-renaming transformers take only 3 args
- (lambda (exp name? rename compare)
- (transformer exp rename compare))))))
- (make-immutable!
- (really-make-transform 'macro proc env type aux-names source id)))))))
- ;; for backwards compatibility with the PreScheme compiler
- (define make-transform make-transform/macro)
- (define (make-transform/inline thing env type source id)
- (let ((type (if (or (pair? type)
- (symbol? type))
- (sexp->type type #t)
- type)))
- (make-immutable!
- (really-make-transform 'inline (car thing) env type (cdr thing) source id))))
- (define-record-discloser :transform
- (lambda (m) (list 'transform (transform-id m))))
- ;; See also: Rees, "Implementing Lexically Scoped Macros",
- ;; Lisp Pointers VI(1), January-March 1993
- (define (maybe-apply-macro-transform transform exp parent-name env-of-use)
- (let* ((token (cons #f #f))
- (new-env (bind-aliases token transform env-of-use))
- (rename (make-name-generator (transform-env transform)
- token
- parent-name))
- (compare (make-keyword-comparator new-env)))
- (values ((transform-procedure transform) exp name? rename compare)
- new-env)))
- (define (apply-inline-transform transform exp parent-name)
- (let* ((env (transform-env transform))
- (rename (make-name-generator env (cons #f #f) parent-name)))
- ((transform-procedure transform) exp env rename)))
- ;; Two keywords are the same if:
- ;; - they really are the same
- ;; - neither one is bound and they have the same symbol in the source
- ;; - they are bound to the same denotation (macro or location or ...)
- (define (make-keyword-comparator environment)
- (lambda (name1 name2)
- (or (eqv? name1 name2)
- (and (name? name1) ;; why might they not be names?
- (name? name2)
- (let ((v1 (lookup environment name1))
- (v2 (lookup environment name2)))
- (if v1
- (and v2 (same-denotation? v1 v2))
- (and (not v2)
- (equal? (name->source-name name1)
- (name->source-name name2)))))))))
- ;; Get the name that appeared in the source.
- (define (name->source-name name)
- (if (generated? name)
- (name->source-name (generated-name name))
- name))
- ;; The env-of-definition for macros defined at top-level is a package,
- ;; and the package system will take care of looking up the generated
- ;; names.
- (define (bind-aliases token transform env-of-use)
- (let ((env-of-definition (transform-env transform)))
- (if (compiler-env? env-of-definition)
- (make-compiler-env
- (lambda (name)
- (if (and (generated? name)
- (eq? (generated-token name)
- token))
- (lookup env-of-definition (generated-name name))
- (lookup env-of-use name)))
- (lambda (name type . rest)
- (assertion-violation 'bind-aliases "no definitions allowed" name))
- (comp-env-macro-eval env-of-use)
- #f)
- env-of-use)))
- ;; Generate names for bindings reached in ENV reached via PARENT-NAME.
- ;; The names are cached to preserve identity if they are bound. TOKEN
- ;; is used to identify names made by this generator.
- (define (make-name-generator env token parent-name)
- (let ((alist '())) ;list of (symbol . generated)
- (lambda (name)
- (if (name? name)
- (let ((probe (assq name alist)))
- (if probe
- (cdr probe)
- (let ((new-name (make-generated name token env parent-name)))
- (set! alist (cons (cons name new-name)
- alist))
- new-name)))
- (assertion-violation 'make-name-generator
- "non-name argument to rename procedure"
- name parent-name)))))
|