transform.scm 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. ;;; Ported from Scheme 48 1.9. See file COPYING for notices and license.
  2. ;;;
  3. ;;; Port Author: Andrew Whatson
  4. ;;;
  5. ;;; Original Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Will Noble
  6. ;;;
  7. ;;; scheme48-1.9.2/scheme/bcomp/transform.scm
  8. ;;;
  9. ;;; Transforms
  10. ;;;
  11. ;;; A transform represents a source-to-source rewrite rule: either a
  12. ;;; macro or an in-line procedure.
  13. (define-module (prescheme bcomp transform)
  14. #:use-module (srfi srfi-9)
  15. #:use-module (prescheme scheme48)
  16. #:use-module (prescheme record-discloser)
  17. #:use-module (prescheme bcomp binding)
  18. #:use-module (prescheme bcomp cenv)
  19. #:use-module (prescheme bcomp mtype)
  20. #:use-module (prescheme bcomp name)
  21. #:use-module (prescheme bcomp transform4)
  22. #:export (make-transform/macro
  23. make-transform/inline
  24. maybe-apply-macro-transform
  25. apply-inline-transform
  26. transform?
  27. transform-kind
  28. transform-type
  29. transform-env ;; These are used to reify transforms.
  30. transform-aux-names
  31. transform-source
  32. transform-id
  33. make-transform))
  34. (define-record-type :transform
  35. (really-make-transform kind xformer env type aux-names source id)
  36. transform?
  37. ;; macro or inline
  38. (kind transform-kind)
  39. (xformer transform-procedure)
  40. (env transform-env)
  41. (type transform-type)
  42. (aux-names transform-aux-names) ;;for reification
  43. (source transform-source) ;;for reification
  44. (id transform-id))
  45. (define (make-transform/macro thing env type source id)
  46. (let ((type (if (or (pair? type)
  47. (symbol? type))
  48. (sexp->type type #t)
  49. type)))
  50. (call-with-values
  51. (lambda ()
  52. (if (pair? thing)
  53. (values (car thing) (cdr thing))
  54. (values thing #f)))
  55. (lambda (transformer aux-names)
  56. ;; The usual old-style transformers take 3 args: exp rename compare.
  57. ;; However, syntax-rules-generated transformers need a 4th arg, name?.
  58. ;; Distinguish between the two kinds.
  59. (let ((proc
  60. (cond
  61. ((explicit-renaming-transformer/4? transformer)
  62. (explicit-renaming-transformer/4-proc transformer))
  63. (else ;; standard explicit-renaming transformers take only 3 args
  64. (lambda (exp name? rename compare)
  65. (transformer exp rename compare))))))
  66. (make-immutable!
  67. (really-make-transform 'macro proc env type aux-names source id)))))))
  68. ;; for backwards compatibility with the PreScheme compiler
  69. (define make-transform make-transform/macro)
  70. (define (make-transform/inline thing env type source id)
  71. (let ((type (if (or (pair? type)
  72. (symbol? type))
  73. (sexp->type type #t)
  74. type)))
  75. (make-immutable!
  76. (really-make-transform 'inline (car thing) env type (cdr thing) source id))))
  77. (define-record-discloser :transform
  78. (lambda (m) (list 'transform (transform-id m))))
  79. ;; See also: Rees, "Implementing Lexically Scoped Macros",
  80. ;; Lisp Pointers VI(1), January-March 1993
  81. (define (maybe-apply-macro-transform transform exp parent-name env-of-use)
  82. (let* ((token (cons #f #f))
  83. (new-env (bind-aliases token transform env-of-use))
  84. (rename (make-name-generator (transform-env transform)
  85. token
  86. parent-name))
  87. (compare (make-keyword-comparator new-env)))
  88. (values ((transform-procedure transform) exp name? rename compare)
  89. new-env)))
  90. (define (apply-inline-transform transform exp parent-name)
  91. (let* ((env (transform-env transform))
  92. (rename (make-name-generator env (cons #f #f) parent-name)))
  93. ((transform-procedure transform) exp env rename)))
  94. ;; Two keywords are the same if:
  95. ;; - they really are the same
  96. ;; - neither one is bound and they have the same symbol in the source
  97. ;; - they are bound to the same denotation (macro or location or ...)
  98. (define (make-keyword-comparator environment)
  99. (lambda (name1 name2)
  100. (or (eqv? name1 name2)
  101. (and (name? name1) ;; why might they not be names?
  102. (name? name2)
  103. (let ((v1 (lookup environment name1))
  104. (v2 (lookup environment name2)))
  105. (if v1
  106. (and v2 (same-denotation? v1 v2))
  107. (and (not v2)
  108. (equal? (name->source-name name1)
  109. (name->source-name name2)))))))))
  110. ;; Get the name that appeared in the source.
  111. (define (name->source-name name)
  112. (if (generated? name)
  113. (name->source-name (generated-name name))
  114. name))
  115. ;; The env-of-definition for macros defined at top-level is a package,
  116. ;; and the package system will take care of looking up the generated
  117. ;; names.
  118. (define (bind-aliases token transform env-of-use)
  119. (let ((env-of-definition (transform-env transform)))
  120. (if (compiler-env? env-of-definition)
  121. (make-compiler-env
  122. (lambda (name)
  123. (if (and (generated? name)
  124. (eq? (generated-token name)
  125. token))
  126. (lookup env-of-definition (generated-name name))
  127. (lookup env-of-use name)))
  128. (lambda (name type . rest)
  129. (assertion-violation 'bind-aliases "no definitions allowed" name))
  130. (comp-env-macro-eval env-of-use)
  131. #f)
  132. env-of-use)))
  133. ;; Generate names for bindings reached in ENV reached via PARENT-NAME.
  134. ;; The names are cached to preserve identity if they are bound. TOKEN
  135. ;; is used to identify names made by this generator.
  136. (define (make-name-generator env token parent-name)
  137. (let ((alist '())) ;list of (symbol . generated)
  138. (lambda (name)
  139. (if (name? name)
  140. (let ((probe (assq name alist)))
  141. (if probe
  142. (cdr probe)
  143. (let ((new-name (make-generated name token env parent-name)))
  144. (set! alist (cons (cons name new-name)
  145. alist))
  146. new-name)))
  147. (assertion-violation 'make-name-generator
  148. "non-name argument to rename procedure"
  149. name parent-name)))))