transform.scm 4.7 KB

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