syntax-rules-apply.scm 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Mike Sperber
  3. ; We compile each rule into a pattern and template which are then used at
  4. ; expansion time. The compiler performs error checking, replaces pattern
  5. ; variables and ellipses with markers, and lists the introduced variables.
  6. ;
  7. ; Expansion is done in three steps:
  8. ; - see if the pattern matches
  9. ; - build the pattern-variable environment
  10. ; - instantiate the template
  11. ; We could match the pattern and build the environment in a single pass, but
  12. ; separating them is simpler and may be faster for complex macros, as it
  13. ; avoids creating partial environments which are then discarded when the
  14. ; match fails.
  15. ;
  16. ; This would all be simple if it weren't for the ellipses.
  17. ;
  18. ; RANK is the ellipsis depth, initially zero.
  19. ;----------------------------------------------------------------
  20. ; This is the expansion part. All it shares with the definition part
  21. ; is the format of the patterns and templates.
  22. (define (apply-rules form rules name? rename compare)
  23. (let ((lose (lambda () form)) ; must be tail-called
  24. (body (cdr form))) ; drop the macro's name
  25. (let loop ((rules rules))
  26. (cond ((null? rules)
  27. (lose))
  28. ((match? (caar rules) body name? rename compare)
  29. (rewrite (cdar rules) ; template
  30. (make-pattern-env (caar rules) body)
  31. name?
  32. rename
  33. lose))
  34. (else
  35. (loop (cdr rules)))))))
  36. (define (match? pattern form name? rename compare)
  37. (let label ((pattern pattern) (form form))
  38. (cond ((pair? pattern)
  39. (and (pair? form)
  40. (label (car pattern) (car form))
  41. (label (cdr pattern) (cdr form))))
  42. ((name? pattern)
  43. (and (name? form)
  44. (compare form (rename pattern))))
  45. ((pattern-variable? pattern)
  46. #t)
  47. ((ellipsis-form? pattern)
  48. (let loop ((form form))
  49. (or (null? form)
  50. (and (pair? form)
  51. (label (ellipsis-form-body pattern) (car form))
  52. (loop (cdr form))))))
  53. ((vector-marker? pattern)
  54. (and (vector? form)
  55. (label (vector-marker-contents pattern)
  56. (vector->list form))))
  57. (else
  58. (equal? pattern form)))))
  59. (define (make-pattern-env pattern form)
  60. (let label ((pattern pattern) (form form) (pattern-env '()))
  61. (cond ((pair? pattern)
  62. (label (cdr pattern)
  63. (cdr form)
  64. (label (car pattern) (car form) pattern-env)))
  65. ((pattern-variable? pattern)
  66. (cons (cons pattern form)
  67. pattern-env))
  68. ((ellipsis-form? pattern)
  69. (let ((envs (map (lambda (form)
  70. (label (ellipsis-form-body pattern)
  71. form
  72. '()))
  73. form)))
  74. (append (map (lambda (var)
  75. (cons var
  76. (map (lambda (env)
  77. (cdr (assq var env)))
  78. envs)))
  79. (ellipsis-form-vars pattern))
  80. pattern-env)))
  81. ((vector-marker? pattern)
  82. (label (vector-marker-contents pattern)
  83. (vector->list form)
  84. pattern-env))
  85. (else
  86. pattern-env))))
  87. (define (rewrite template pattern-env name? rename lose)
  88. (let label ((template template) (pattern-env pattern-env))
  89. (cond ((null? template)
  90. '())
  91. ((pair? template)
  92. ((if (ellipsis-form? (car template))
  93. append
  94. cons)
  95. (label (car template) pattern-env)
  96. (label (cdr template) pattern-env)))
  97. ((name? template)
  98. (rename template))
  99. ((pattern-variable? template)
  100. (cdr (assq template pattern-env)))
  101. ((ellipsis-form? template)
  102. (rewrite-ellipsis label lose template pattern-env))
  103. ((vector-marker? template)
  104. (list->vector (label (vector-marker-contents template)
  105. pattern-env)))
  106. (else
  107. template))))
  108. (define (rewrite-ellipsis label lose template pattern-env)
  109. (let ((template (ellipsis-form-body template))
  110. (vars (ellipsis-form-vars template)))
  111. (let ((vals (map (lambda (var)
  112. (reverse (cdr (assq var pattern-env))))
  113. vars)))
  114. (if (or (null? (cdr vals))
  115. (apply = (map length vals)))
  116. (let loop ((vals vals) (results '()))
  117. (if (null? (car vals))
  118. results
  119. (loop (map cdr vals)
  120. ((if (ellipsis-form? template)
  121. append
  122. cons)
  123. (label template
  124. (append (map (lambda (var vals)
  125. (cons var (car vals)))
  126. vars
  127. vals)
  128. pattern-env))
  129. results))))
  130. (lose)))))